知識の枝

"All is well"

スクレイピングで情報収集を効率良く!追記

約442日前 2020年9月10日23:04
デジタル
Python

改訂履歴


2020/9/10 投稿

1. 背景


こちらの記事は「スクレイピングで情報収集を効率良く!」の追記です。
内容を修正した箇所について、こちらで解説します。

2. プログラムの中身


まず修正前のプログラムを下記に示します。
from bs4 import BeautifulSoup
import urllib.parse as par
import urllib.request as req
import pandas as pd
import datetime

keywords = ['スクレイピング']
URL_encoded = []
title_list = []
url_list = []

for ja in keywords:
URL_encoded.append(par.quote(ja))

for word in range(len(keywords)):
for page in range(2):
url = "https://crowdworks.jp/public/jobs/search?hide_expired=true&keep_search_criteria=true&order=score&page=" + str(page) + "&search%5Bkeywords%5D=" + URL_encoded[word]

response = req.urlopen(url)

parse_html = BeautifulSoup(response, 'html.parser')

title_lists = parse_html.find_all('a')

for i in title_lists:
title_list.append(i.string)
url_list.append('https://crowdworks.jp' + i.attrs['href'])

df_title_url = pd.DataFrame({'Title': title_list, 'URL': url_list})

df_notnull = df_title_url.dropna(how='any')

df_contain_python = df_notnull[df_notnull['Title'].str.contains(keywords[word])]

df_contain_python = df_contain_python[~df_contain_python['Title'].str.contains('スクレイピング以外|スクレイピング未使用')]

df_contain_python.to_csv(str(datetime.date.today()) + '_output.csv', encoding='utf_8_sig')

こちらのプログラムの問題は、
forループ内で下記の除去コマンドを実行していたことでした。
df_notnull = df_title_url.dropna(how='any')
df_contain_python = df_notnull[df_notnull['Title'].str.contains(keywords[word])]
df_contain_python = df_contain_python[~df_contain_python['Title'].str.contains('スクレイピング以外|スクレイピング未使用')]

特に問題なのが2行目の
「df_contain_python = df_notnull[df_notnull['Title'].str.contains(keywords[word])]」です。

データフレーム内の全ての「Title」要素に対し、指定したキーワード「keywords[word]」が入っていいない要素を削除するコマンドです。
(欲しい情報のみを残す機能です)

仮に検索キーワードを複数用意していた場合、
一番最後のキーワードの要素だけを残し、せっかく集めた他のキーワードの要素を削除してしまいます。

修正後は検索キーワードが複数あっても全て残るようにします。

修正済のプログラムを下記に示します。
from bs4 import BeautifulSoup
import urllib.parse as par
import urllib.request as req
import pandas as pd
import datetime

keywords = [
'スクレイピング',
'デザイン',
'ナレーション'
]
URL_encoded = []
title_list = []
url_list = []

for ja in keywords:
URL_encoded.append(par.quote(ja)) #日本語をURLエンコード

for word in range(len(keywords)): #キーワードの数だけforloop
for page in range(5): #Xページ目まで取得
url = "https://crowdworks.jp/public/jobs/search?hide_expired=true&keep_search_criteria=true&order=score&page=" + str(page) + "&search%5Bkeywords%5D=" + URL_encoded[word]
response = req.urlopen(url) #URLを開く

parse_html = BeautifulSoup(response, 'html.parser')

title_lists = parse_html.find_all('a')

for i in title_lists:
title_list.append(i.string)
url_list.append('https://crowdworks.jp' + i.attrs['href']) #引き抜くURLがドメイン以降の文字列の為、ドメイン部分を追加しておく。

df_title_url = pd.DataFrame({'Title': title_list, 'URL': url_list}) #データフレーム作成

df_notnull = df_title_url.dropna(how='any') #nullデータを除去

df_droptitle = df_notnull[~df_notnull['Title'].str.contains('ウェブ|以外')] #Titleから除きたいワード

df_dropurl = df_droptitle[~df_droptitle['URL'].str.contains('group|sgroup|category|employers')] #除きたいURL(/group, /sgroup, /category, /employers)

df_contain = df_dropurl[df_dropurl['Title'].str.contains(str('|'.join(keywords)))] #タイトルに検索ワード含むもののみを残す

df_contain.to_csv(str(datetime.date.today()) + '_output.csv', encoding='utf_8_sig') #csvファイル化、文字エンコード

大きな違いは「データフレーム作成」以降をforループから外したところです。

また問題だった除去文は下記のように変更しました。
df_contain = df_dropurl[df_dropurl['Title'].str.contains(str('|'.join(keywords)))]

検索キーワードを「joinメソッド」で結合しています。

具体的には下記のようになっています。
'|'.join(keywords) → スクレイピング|デザイン|ナレーション
str(スクレイピング|デザイン|ナレーション) → 'スクレイピング|デザイン|ナレーション'

「keywords」リストの中身を全て抜き出し、「|」で区切って繋げています。
※「|」は「Shift」+「¥」で表示されます。バーティカルバーといいます。

こうすることで、データフレームの中身の欲しい情報を間違って消すことが無くなります。

プログラムの修正は以上です。
質問がありましたらコメントをお願いします。