就活サイトからESをかっさらってくる。

最近、機械学習用の言語データがないかなーって探していたんですけど、いい情報がなくて諦めていました。 そしたらたまたま、いい記事を見つけたので真似をしてみることに。

それがこちらの記事 この記事はunistyleに公開されているESをスクレイピングによって取得するというものでした。

しかし、この記事は2年前に執筆されており、実行すると不具合が出ました。 そこで、コードを修正(コードの可読性、効率は悪くなった、、、)し、ここに記録として載せました。

それが以下のコード

#coding:utf-8
PURPLE  = '\033[35m'
RED     = '\033[31m'
CYAN    = '\033[36m'
OKBLUE  = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL    = '\033[91m'
ENDC    = '\033[0m'

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
from bs4 import BeautifulSoup
from extractcontent3 import ExtractContent
import pickle
import sys

##### ExtractContent(only fetch contents)########
def extractor(html):
    extractor = ExtractContent()
    opt = {"threshold":50}
    extractor.analyse(html)
    text, title = extractor.as_text()
    return text


email = 'USER_ID'
password = 'USER_PASSWORD'
LOGIN_URL= 'https://unistyleinc.com/'

# Log in
options = Options()
options.binary_location = "/usr/bin/google-chrome"
b = webdriver.Chrome(chrome_options = options, executable_path='./chromedriver')
b.get(LOGIN_URL)
b.find_element_by_id('LoginLink').click()
b.find_element_by_name('user[email]').send_keys(email)
b.find_element_by_name('user[password]').send_keys(password)
b.find_element_by_class_name('login_submit').click()

def first():
    # Move to categories
    time.sleep(0.1)
    b.get('https://unistyleinc.com/categories')
    category = b.find_element_by_class_name('es_category_list')
    a = category.find_elements_by_css_selector("a")
    dict_category = {}
    for total,i in enumerate(a):
        if not total == int(category_num):
            continue
        name = str(i.text.replace('>',''))
        URL  = str(i.get_attribute("href"))
        print ('STEP1 : '+str(total+1)+'/'+str(len(a))+' '+name+'--->'+OKBLUE+URL+ENDC)
        dict_category[name]=URL

    # Move to company from the category
    dict_company = {}
    for name in dict_category:
        URL = dict_category[name]
        b.get(URL)
        time.sleep(0.1)
        companies = b.find_element_by_class_name('essearch_common_wrap')
        a = companies.find_elements_by_css_selector("a")
        for i in a:
            company = str(i.text.split(' ')[0])
            URL  = str(i.get_attribute("href"))
            if URL != 'https://unistyleinc.com/categories':
                dict_company[company] = URL
                print ('STEP2 : '+company+'--->'+OKGREEN+URL+ENDC)

    # 本選考などESpageを取得
    dict_kindofES = {}
    for company in dict_company:
        URL = dict_company[company]
        b.get(URL)
        time.sleep(0.1)
        ESs = b.find_element_by_class_name('essearch_common_wrap')
        a = ESs.find_elements_by_css_selector("a")
        
        count = 0
        for i in a:
            cmp = str(i.text.split(' ')[0])
            URL  = str(i.get_attribute("href"))
            if count != 0 and URL != 'https://unistyleinc.com/categories':
                dict_kindofES[company+cmp] = URL
                print ('STEP3 : '+company+cmp+'--->'+OKGREEN+URL+ENDC)
            count = count + 1

    # Move to (ES/interview/OB visit etc...)page from company URL
    dict_com_url = {}
    for company in dict_kindofES:
        URL = dict_kindofES[company]
        b.get(URL)
        def get_ES_URL(b,dict_com_url):
            time.sleep(0.1)
            list_ES = b.find_elements_by_class_name('es_container')
            for i in list_ES:
                a = i.find_element_by_css_selector("a")
                url   = str(a.get_attribute("href"))
                print ('STEP4 : '+company+'--->'+PURPLE+url+ENDC)
                dict_com_url.setdefault(company, []).append(url)

        ES_page_number = b.find_elements_by_class_name('fg essearch_page_btn')
        if not len(ES_page_number) == 0:
            for epn in ES_page_number:
                a = epn.find_element_by_css_selector("a")
                EsPageUrl = str(a.get_attribute("href"))
                b.get(EsPageUrl)
                get_ES_URL(b,dict_com_url)
        else:
            get_ES_URL(b,dict_com_url)
    with open('./dict_com_url.pickle', mode='wb') as f:        
        pickle.dump(dict_com_url,f)
        
def second():
    with open('./dict_com_url.pickle', mode='rb') as f:
        dict_com_url = pickle.load(f)
    #Save contents
    W = open('result'+args[2]+'.csv','w')
    W.write('ID,Company,URL,Contents\n')
    num = 0
    code = 0
    dict_com_url_count = 0
    for key in dict_com_url:
        list_URL = dict_com_url[key]
        for j,URL in enumerate(list_URL):
            try:
                b.get(URL)
                time.sleep(0.1)
                html = b.page_source
                text = extractor(html)
                # text = text.replace(',','').replace('\n',' ').replace('\t','').replace('\r','')
                text = text.replace(',',',')
                print ('STEP5 : '+key+'--->'+PURPLE+URL+ENDC)
                print (text[:100]+'...')
                W.write(str(num)+','+key+','+URL+','+text+'\n')
            except:
                # print ('request error')
                code = 1
                break
            num+=1
        if code == 1:
            print("システムが終了しました。\n最終実行はdic_com_url:"+str(dict_com_url_count)+"番のlist_URL:"+str(j)+"番です。")
            break
        dict_com_url_count += 1
    W.close()

def therd():
    with open('./dict_com_url.pickle', mode='rb') as f:
        dict_com_url = pickle.load(f)
    #Save contents
    W = open('result'+args[2]+'.csv','a')
    num = int(args[3])
    code = 0
    dict_com_url_count = 0
    for i,key in enumerate(dict_com_url):
        if i >= int(args[3]):
            list_URL = dict_com_url[key]
            for j,URL in enumerate(list_URL):
                if i == int(args[3]) and j < int(args[4]):
                    continue
                try:
                    b.get(URL)
                    time.sleep(0.1)
                    html = b.page_source
                    text = extractor(html)
                    text = text.replace(',',',')
                    print ('STEP5 : '+key+'--->'+PURPLE+URL+ENDC)
                    print (text[:100]+'...')
                    W.write(str(num)+','+key+','+URL+','+text+'\n')
                except:
                    code = 1
                    break
                num+=1
            if code == 1:
                print("システムが終了しました。\n最終実行はdic_com_url:"+str(dict_com_url_count)+"番のlist_URL:"+str(j)+"番です。")
                break
            dict_com_url_count += 1
    W.close()

args = sys.argv
category_num = args[2]

if args[1] == "1":
    first()
elif args[1] == "2":
    second()
elif args[1] == "3":
    therd()
else:
    print(args+"が入力されました\n第一引数:シーケンス番号,第二引数:カテゴリ番号,第三引数:中途開始番号1,第四引数:中途開始番号2")

このコードは2回、ないし3回実行することが必要です。

実行は

python3 Scraping.py 1 [企業カテゴリ番号(0-35)]
python3 Scraping.py 2 [企業カテゴリ番号(0-35)]

しかし、seleniumの影響でスクレイピング数が変化します。 なので、もし途中で止まった場合、どこで止まったか最後に表示するようにしているので、 その続きから実行するために

python3 Scraping.py 3 [企業カテゴリ番号(0-35)] [中途開始番号1] [中途開始番号2]

として、エラーなく最後まで実行できるようにします。 また、これでもまだ途中で止まる可能性があるので、その場合は途中開始番号1に前回の途中開始番号1を足した値を入れてあげることで またその続きから実行できます。

お粗末な改修プログラムですが、誰かのお役にたてますように