今回の内容
前回のコピペでスクレイピング③ クラウドワークスの新着情報を収集で取得したデータを過去のデータと比較し、新着があれば抽出します。
前回作ったコードを出力
前回、下記のようなコードを書きました
これに追記してテスト用に出力できるようにします。
# 旧リスト保存用ファイル
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
コードの下部に下記のコードを追加します。
# 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']
.......
このように一連のデータが取得できれば成功です。
新着(差分)データを抽出する
# 差分比較
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に含まれているため、抽出が容易でした。
このあたりが差分比較のポイントになると思います。
上記のコードでは旧データのファイルが無い場合の処理が入っていません。
また、この段階では新データは保存していませんが、それはまとめて次回の処理で行います。
また次回もよろしくお願いいたします。