LoginSignup
1
4

More than 1 year has passed since last update.

コピペでスクレイピング④ クラウドワークスの新着情報を収集

Last updated at Posted at 2022-09-17

今回の内容

前回のコピペでスクレイピング③ クラウドワークスの新着情報を収集で取得したデータを過去のデータと比較し、新着があれば抽出します。

前回作ったコードを出力

前回、下記のようなコードを書きました
これに追記してテスト用に出力できるようにします。

scray_data.py
# 旧リスト保存用ファイル
path = os.getcwd()
data_file = os.path.join(path, 'crowdworks.txt')
# メール送信用データ保存先
send_file = os.path.join(path, 'send.txt')

def new_data_get(target_url):
    res = st.source_code_get(target_url)
    soup = BeautifulSoup(res, "lxml")
    # 1
    title_tags = soup.select(
        '#result_jobs > div.search_results > ul > li > div > div >'
        ' div.item_body.job_data_body > div.job_data_row > div.job_data_column.summary > h3 > a')
    list_datas = []
    # print(title_tags)

    for title_tag in title_tags:
        # 2
        item_name = title_tag.text
        # 3
        item_url = main_url + title_tag.get('href')
        # urlの末尾の番号がユニークなのでIDとして取得
        # 4
        item_id = item_url.split('/')[-1]

        # 5 データをまとめる
        list_datas.append([item_id, item_name, item_url])
    return list_datas

コードの下部に下記のコードを追加します。

scray_data.py
# 1
if __name__ == '__main__':
    # URL ==============================================================================
    main_url = 'https://www.crowdworks.jp'
    keyword = 'スクレイピング'
    target_url = f'https://crowdworks.jp/public/jobs/search?keep_search_criteria=' \
                 f'true&order=score&hide_expired=false&search[keywords]={keyword}'
    # ==================================================================================
# 2
    list_datas = new_data_get(target_url)
    for list_data in list_datas:
        print(list_data)
# 1
if __name__ == '__main__':

#1
これは、scray_data.pyファイルが直接読み込まれたときだけ実行するという意味です。
詳しく書くと長くなりますが、import ~ で他のファイルから読み込んだ時は実行されません。
これを今回は動作確認用として使用します

#2
コピペでスクレイピング② クラウドワークスの新着情報を収集で作ったキーワードを合成したURL

    keyword = 'スクレイピング'
    target_url = f'https://crowdworks.jp/public/jobs/search?keep_search_criteria=' \
                 f'true&order=score&hide_expired=false&search[keywords]={keyword}

をtarget_urlに代入して関数の引数として与えます。

# 2
    list_datas = new_data_get(target_url)
    for list_data in list_datas:
        print(list_data)

では、scray_data.pyを実行してみます。
コマンドプロンプト若しくはターミナルでscray_data.pyを保存したディレクトリに移動し、
Windwosであれば

py scray_data.py

Linun、Macであれば

python scray_data.py 
または
python3 scray_data.py

で実行できると思います

====== WebDriver manager ======
Current google-chrome version is 105.0.5195
Get LATEST chromedriver version for 105.0.5195 google-chrome
Driver [C:\Users\fujitsu\.wdm\drivers\chromedriver\win32\105.0.5195.52\chromedriver.exe] found in cache
['8105422', 'pythonを利用したスクレイピング機能の開発', 'https://www.crowdworks.jp/public/jobs/8105422']
['7850193', '【Ruby on Rails】でのスクレイピングシステムの追加・修正', 'https://www.crowdworks.jp/public/jobs/7850193']
['7705652', 'スクレイピング作業', 'https://www.crowdworks.jp/public/jobs/7705652']
['8157210', '【GAS】4つのWebサイトからスクレイピングしスプレッドシートに保存', 'https://www.crowdworks.jp/public/jobs/8157210']
['8053755', '楽天、YAHOO!、Amazonの購入履歴情報の収集ツール作成', 'https://www.crowdworks.jp/public/jobs/8053755']
['8156120', '「スクレイピング・データ収集」のお仕事のご相談(建設・不動産)', 'https://www.crowdworks.jp/public/jobs/8156120']
['8144592', 'ヤフオク特定商品の価格取得', 'https://www.crowdworks.jp/public/jobs/8144592']
['8093442', 'SNS媒体でのスクレイピング抽出プログラムの構築【応募方法参照・外国人不可・テンプレート応募不可】', 'https://www.crowdworks.jp/public/jobs/8093442']
['8157251', '指定したサイトの企業一覧をスプレッドシートかエクセルに吐き出してほしい', 'https://www.crowdworks.jp/public/jobs/8157251']
['8118501', '指定サイトの情報を収集するツール', 'https://www.crowdworks.jp/public/jobs/8118501']
['8113262', 'eBay用API・スクレイピングによる新規出品システムの不具合修正', 'https://www.crowdworks.jp/public/jobs/8113262']
['8128463', '指定サイトからデータ収集し、弊社サイトへの反映', 'https://www.crowdworks.jp/public/jobs/8128463']
['8098855', '情報サイトの情報移転', 'https://www.crowdworks.jp/public/jobs/8098855']
['8159871', 'Googleスプレッドシートに入力したデータをワードプレスにコピぺ可能にする仕組み化を募集します。', 'https://www.crowdworks.jp/public/jobs/8159871']
['8109911', '0907_企業情報を収集して、共有するGoogleスプレッドシートに集めていただきたいです!_MF_3020', 'https://www.crowdworks.jp/public/jobs/8109911']
['8159265', '0916_企業情報を収集して、共有するGoogleスプレッドシートに集めていただきたいです!__3020', 'https://www.crowdworks.jp/public/jobs/8159265']
.......

このように一連のデータが取得できれば成功です。

新着(差分)データを抽出する

scray_data.py
# 差分比較
def diff_data_get(list_datas):
    # 返り値用のリスト
    diff_datas = []
    # 旧データの比較用に数値のみ抽出するリスト
    old_datas_num = []

    # 旧データを取得
    with open(data_file, 'r') as f:
        reader = f.readlines()
        old_list_datas = [row for row in reader]
        #  旧リストの番号だけ取得
        for old_list_data in old_list_datas:
            old_datas_num.append(old_list_data.replace('\n', ''))

    # 新リストの番号が旧リストになければdiff_dataリストにして値を返す
    for list_data in list_datas:
        if list_data[0] not in old_datas_num:
            diff_datas.append(list_data)
            # print(list_data)
        else:
            pass
    for diff_data in diff_datas:
        with open(send_file, 'a', encoding='utf-8') as f:
            f.write(f'{diff_data[0]}  {diff_data[1]}  {diff_data[2]}\n')

    return diff_datas

上記が新着を抽出する関数です。

def diff_data_get(list_datas):
    # 返り値用のリスト
    diff_datas = []
    # 旧データの比較用に数値のみ抽出するリスト
    old_datas_num = []

まず、差分抽出関数を『diff_data_get(list_datas):』とし、
先程、『new_data_get(target_url)』で得られた返り値をlist_datasに代入します。
diff_datas = [] は新着のデータを格納します。
old_data_num = [] は前回の案件のデータを格納するのですが、案件の番号のみを保存しています。
案件の番号さえわかれば比較できるし、文字列同士を比較するより精度が良いので過去データには番号のみ保存しています。保存の部分については後述します。

テキストファイルの読み込み元

# 旧リスト保存用ファイル
path = os.getcwd()
data_file = os.path.join(path, 'crowdworks.txt')
# メール送信用データ保存先
send_file = os.path.join(path, 'send.txt')

コメント通りなのですが、data_file とsend_fileのパスを指定しています。

    # 旧データを取得
    with open(data_file, 'r') as f:
        reader = f.readlines()
        old_list_datas = [row for row in reader]
        #  旧リストの番号だけ取得
        for old_list_data in old_list_datas:
            old_datas_num.append(old_list_data.replace('\n', ''))

data_file(中身はcrowdworks.txt)ファイルを呼び出し、配列としてold_list_datasに格納しています。そして、old_list_datasから、番号だけを抜き出し、改行記号”/n"を削除してold_data_numに格納しました。
削除記号はテキストファイルに保存するときに勝手に入るので、これを削除しないと新旧データの比較ができなくなります。そのために削除しました。

データ比較

    # 新リストの番号が旧リストになければdiff_dataリストにして値を返す\
    #3
    for list_data in list_datas:
        if list_data[0] not in old_datas_num:
            diff_datas.append(list_data)
            # print(list_data)
        else:
            pass
    #4
    Gmail用ファイルに出力
    for diff_data in diff_datas:
        with open(send_file, 'a', encoding='utf-8') as f:
            f.write(f'{diff_data[0]}  {diff_data[1]}  {diff_data[2]}\n')

    return diff_datas

#3
for文でlist_datasから配列で格納されている1案件分のデータを抜き出し、lidt_data[0]で、案件の番号のみを抜き出して、if ~ in で、old_data_numと比較しています。
old_data_numに含まれていない場合はdiff_datasに配列として格納します。
格納する時はlist_data[0]などと、要素を限定していないのでデータ全部が格納されます。
elseの場合、
新データ番号が旧データ番号に含まれている場合は処理をスキップします。

#4
上記の処理でdiff_datasに格納されたデータはGmail送信用ファイルとしてsend_fileに保存します。
send_fileに保存するときに

f.write(f'{diff_data[0]}  {diff_data[1]}  {diff_data[2]}\n')

としているのは配列などで格納すると、Gmailメッセージとして送信する時、余計な記号が入るのを防止するためです。上記のように値を指定して保存し、最後に改行を入れておくと、Gmailで送信したときに読みやすくなります。

まとめ

今回は新旧データの差分比較を行いました。
ポイントは文字列抽出だと時々誤作動が起こるため、一意の数字を見つけて比較するところです。
一意の数字は、URLに含まれている場合と、WEBページの何処かにある場合、そのサイトによって色々あると思います。クラウドワークスの場合はURLに含まれているため、抽出が容易でした。
このあたりが差分比較のポイントになると思います。

上記のコードでは旧データのファイルが無い場合の処理が入っていません。
また、この段階では新データは保存していませんが、それはまとめて次回の処理で行います。
また次回もよろしくお願いいたします。

1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4