Seleniumで満足に自動化処理ができるようになったので、今度はハローワークの求人情報を自動的に取得して、その内容をメールで通知するプログラムを作ってみました。

もちろん、cronにも対応しています。これで求人情報をチェックする面倒な作業を自動化できるでしょう。

プログラムの概要

フローチャート図

フローチャート図

Seleniumでの文字入力とクリック作業が主体です。

ソースコード

#! /usr/bin/python3
import bs4,requests,time,os,sys,random,re,csv
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.common.alert import Alert
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import Firefox, FirefoxOptions

#メール送信関係
import smtplib
from email.mime.text import MIMEText
from email.header import Header

#メールの文字コード、送信元、パスワード、宛先の指定
mail_data_file          = open("./mail_data.txt")
raw_mail_data           = mail_data_file.readlines()
mail_data_file.close()

for i in range(len(raw_mail_data)):
    raw_mail_data[i] = re.sub(r"\n","",raw_mail_data[i])

charset         = raw_mail_data[0]
from_email      = raw_mail_data[1]
from_email_pass = raw_mail_data[2]
to_email        = raw_mail_data[3]

#ヘッドレスモードで起動させる。
options = FirefoxOptions()
options.add_argument('-headless')

browser = webdriver.Firefox(options=options)
browser.get("https://www.hellowork.go.jp/servicef/130020.do?action=initDisp&screenId=130020")

TIMEOUT         = 10
WAIT_TIME       = 0.5
ORIGINAL_URL    = "https://www.hellowork.go.jp/servicef/"

def get_work_info():

    output_list     = []

    try:
        html_wait = WebDriverWait(browser,3)
        print("HTML取得中")
        html_elem = html_wait.until(expected_conditions.visibility_of_element_located((By.TAG_NAME, "html")))
        print("HTML取得完了")
    except:
        print("HTMLの取得に失敗しました")

    else:
        
        #雇用形態と都道府県を指定
        part_time       = browser.find_element_by_id("ID_LkyujinShurui2")
        part_time.click()
        area            = browser.find_element_by_id("ID_todofuken34")
        area.click()

        #検索を行う
        html_wait = WebDriverWait(browser,TIMEOUT)
        botton_elem = html_wait.until(expected_conditions.visibility_of_element_located((By.XPATH, "//input[@value='検索']")))
        y_pos = botton_elem.location["y"]
        #ハローワークではscrollToが使えないので注意。
        browser.execute_script("window.scroll(0 , " + str(y_pos) + ");")
        time.sleep(WAIT_TIME)
        botton_elem.click()

        #===============就業場所の指定======================================================
        html_wait = WebDriverWait(browser,TIMEOUT)
        botton_elem = html_wait.until(expected_conditions.visibility_of_element_located((By.XPATH, "//a[@id='ID_lnkShugyoBasho']")))
        y_pos = botton_elem.location["y"]
        #ハローワークではscrollToが使えないので注意。
        browser.execute_script("window.scroll(0 , " + str(y_pos) + ");")
        time.sleep(WAIT_TIME)
        botton_elem.click()
        
        html_wait = WebDriverWait(browser,TIMEOUT)
        botton_elem = html_wait.until(expected_conditions.visibility_of_element_located((By.XPATH, "//input[@id='ID_chiku1']")))
        y_pos = botton_elem.location["y"]
        #ハローワークではscrollToが使えないので注意。
        browser.execute_script("window.scroll(0 , " + str(y_pos) + ");")
        time.sleep(WAIT_TIME)
        botton_elem.click()
        botton_elem.send_keys("広島市")
        #===============就業場所の指定======================================================


        #===============希望職種の指定======================================================
        html_wait = WebDriverWait(browser,TIMEOUT)
        botton_elem = html_wait.until(expected_conditions.visibility_of_element_located((By.XPATH, "//a[@id='ID_lnkShigotoNaiyo']")))
        y_pos = botton_elem.location["y"]
        #ハローワークではscrollToが使えないので注意。
        browser.execute_script("window.scroll(0 , " + str(y_pos) + ");")
        time.sleep(WAIT_TIME)
        botton_elem.click()


        html_wait = WebDriverWait(browser,TIMEOUT)
        botton_elem = html_wait.until(expected_conditions.visibility_of_element_located((By.XPATH, "//input[@id='ID_kiboShokushu1']")))
        y_pos = botton_elem.location["y"]
        #ハローワークではscrollToが使えないので注意。
        browser.execute_script("window.scroll(0 , " + str(y_pos) + ");")
        time.sleep(WAIT_TIME)
        botton_elem.click()
        botton_elem.send_keys("10")
        #===============希望職種の指定======================================================


        #===============検索ボタンを押す======================================================
        html_wait = WebDriverWait(browser,TIMEOUT)
        botton_elem = html_wait.until(expected_conditions.visibility_of_element_located((By.XPATH, "//input[@id='ID_commonSearch']")))
        y_pos = botton_elem.location["y"]
        #ハローワークではscrollToが使えないので注意。
        browser.execute_script("window.scroll(0 , " + str(y_pos) + ");")
        time.sleep(WAIT_TIME)
        botton_elem.click()
        #===============検索ボタンを押す======================================================


        #BeautifulSoupでパース、リンクの取得
        parsed_page     = bs4.BeautifulSoup(browser.page_source, "lxml")
        job_link        = parsed_page.select(".sole-small > tbody > tr > td > a")
        job_content     = parsed_page.select(".left > div")
        
        for i in range(len(job_content)):
            if i%6 == 0:
                num = i/6
                raw_url         = job_link[int(num)].get("href")
                edited_url      = re.sub(r"^\./","",raw_url)
                combined_url    = ORIGINAL_URL + edited_url
                print("\n" + combined_url)
                output_list.append(combined_url)
            print(job_content[i].text)
            output_list.append(job_content[i].text)

    return output_list

def send_mail(content):

    string = ""

    for i in range(len(content)):
        string = string + str(content[i]) + "\n"
        if (i+1)%7 == 0:
            string = string + "\n"
    string = string + "\n"

    msg = MIMEText("求人情報をお知らせします。\n\n" + string ,"plain",charset)
    msg["Subject"] = Header("ハローワークの求人情報".encode(charset),charset)

    smtp_obj =  smtplib.SMTP("smtp.gmail.com", 587)
    smtp_obj.ehlo()

    smtp_obj.starttls()

    smtp_obj.login(from_email , from_email_pass)
    smtp_obj.sendmail(from_email, to_email , msg.as_string())
    smtp_obj.quit()

    return True

if __name__ == "__main__":
    try:

        send_mail(get_work_info())
        browser.save_screenshot("test.png")
        browser.close()

    except KeyboardInterrupt:
        print("\nprogram was ended.\n")
        sys.exit()

このプログラムでは、パートで広島県広島市のIT系技術職を指定していますが、変数を割り当てれば他の地域や雇用形態も選択可能です。

このプログラムの解説

まず、Seleniumでハローワークの求人検索サイトにアクセスします。雇用形態と地域のチェックボックスをクリックして、検索を開始します。

続いて、就業場所の都市と希望職種を入力して再検索、表示された案件をBeautifulSoupでパースしてメールで送信します。

工夫したところ

処理ごとにコメントで区切る

Seleniumの自動化処理は後でメンテナンスしやすいように、処理ごとにコメントで区切っています。だからソースコードがとても読みやすくなりました。

その反面、変数名がてきとうなので、コメントを削除してしまうとわけがわからなくなるデメリットがありますが。

求人検索に表示されるテーブルの処理

求人情報に表示されるテーブルにはクラス名が指定されておらず、案件情報を個別に抜き出すことはできません。

そのため、forループで案件情報を全て表示した上でURLの併記を繰り返しています。

メール受信後にすぐに案件にアクセスできるようにURLも併記

メールを受信したら、案件にすぐにアクセスできるようにURLも併記しています。

これで案件の詳細情報をスムーズに閲覧することができます。

動作環境

  • Python3.6以上
  • Selenium、BeautifulSoup、lxmlなどのサードパーティ製モジュール

実際に動かしてみる

実際に動かしてみます。プログラムを実行するとFirefoxが起動します。(ただし、ヘッドレスモードが無効化されている場合に限る)

希望条件の指定を全て終えると、案件がテーブルで表示されます。その内容を収集して送信されたメールの内容は以下の通りです。

送信されたメール

ご覧の通り、メールにはテーブルに書かれてある求人案件の簡易情報とURLが掲載されています。

cronの指定も可能で、ヘッドレスモードを有効にしておくだけで毎日定時で処理を行ってくれます。常にハローワークの求人情報を検索したりする面倒はもう不要です。

メリットとデメリット

メリット

  • cronに登録しておくだけで自動的に求人情報を調べてくれる
  • メールで受信したらすぐに求人情報の詳細を調べることができる
  • 更に条件を絞り込むことも可能

cronに登録しておくだけで自動的に求人情報を調べてくれる

cronに登録しておくだけで、自動的に求人情報を調べてくれるようになっています。

例えば、毎日朝6時にハローワークにアクセスして案件の状況をメールで通知してほしい場合はcronに以下のように書き込むと良いでしょう。

00 6 * * * user ./check_hellowork.py

メールで受信したらすぐに求人情報の詳細を調べることができる

メールの本文にはURLが掲載されているので求人情報の詳細をクリック一発で調べることができます。

もちろん、Seleniumの操作を書き換えれば個別に情報の詳細をメールに記載することもできますが、一覧の確認には不便なのであえて実装しませんでした。

更に条件を絞り込むことも可能

Seleniumの操作を書き加えるだけで更に条件を絞り込むことができます。

今回は情報処理の仕事でなおかつ就業場所の地域の指定のみでしたが、資格の有無や給与なども細かく指定可能です。

デメリット

  • 実装が面倒
  • 変数になっていないので求人情報の指定が難しい
  • 1ページまでしか読み込まない

実装が面倒

以前紹介したAmazonのほしい物リストから値下げされた商品をメールで通知するPythonプログラムと同様、メールのパスワード入力やcronの設定、Firefoxのプロファイルの指定など実装までが面倒です。

エンドユーザーへの負担を最小限にするためにも、いずれはこの辺りの作業も自動化させたいと考えています。

変数になっていないので求人情報の指定が難しい

自分用に作ったので、求人情報の指定を変数にしていません。とはいえ、この問題はすぐに修正できるので問題はないでしょう。

1ページまでしか読み込まない

現状ではハローワークで求人検索を行って表示される案件の中から、最初の1ページだけを読み込むようになっています。

2ページ目以降をクリックする仕様にはなっていないので、求人数が増えた場合は改良が必要ですね。もっとも、Seleniumのclickメソッドを使えばそれほど難しくはありません。

結論

これで面倒なハローワークの求人情報の検索がスムーズになります。毎度毎度希望条件をマウスでクリックする必要がなく、自動で通知されるのでとても簡単です。

ハローワークの求人検索サイトに、こんな感じの自動通知の機能がデフォルトで実装されていれば、もっと働きやすいでしょうね。

関連記事

Seleniumでの自動操作+スクレイピング+メール送信

【内部リンク】Amazonのほしい物リストから値下げされた商品をメールで通知するPythonプログラム

同じようなSeleniumでの自動操作+スクレイピング+メール送信には、これがあります。

こちらもcronで動作させることができるので、設定後はほったらかしでもOKです。

Amazon関係のプログラム

【内部リンク】Seleniumを使ってAmazonアソシエイトのリンクタグを画像つきでジェネレートしてみた

こちらもSeleniumを使ってのスクレイピングプログラムです。

自動操作は行っていませんが、Amazonのような動的サイトはSeleniumを使わなければスクレイピングできません。