Webスクレイピング(Scraping)とは、Webサイトから任意の情報を抽出、整形、解析する技術のこと。
私は、この言葉が流行していない2001年頃から、CGI/PHPを使ってベンチャー企業でマッシュアップサービスを作っていた。
他者がWebサーバを通じて提供するソフトウェア機能を積極的に再利用することによって、自らのWebアプリケーションを構築すること
初めてのWebスクレイピング業務は、別サイトに書かれていた大型デパートの「催し物」「イベント」情報を自動的に取得して、地元商店街ポータルサイトの「what’s new」を更新すること。
2002年、大学生時代に作った「マイ・セトラタウン」。
今でも好んでWebスクレイピングを使ったサービスを作っている。
記事のコメントに偏向を感じ、ブラウザのプラグイン目的で作った「Yahooニュースに投稿したユーザランキング」。
遊びまくっていた時代、催し物を逃すまいとTwitterやwebを自動徘徊して生成される「都内週末イベント情報」。
そして、昨年作った「千葉/東京湾の釣れている魚の統計データ」。
が、
このサービスは継続的な運用が非常に大変……。
相手のサイトが仕様・デザインを変えた
場合には、それに合わせた追従が必要となる。
Twitterのサイトを使ったカレンダーサービスは、ツイッター社の度重なるWebスクレイピング禁止の仕組み導入に負けて、サイトは閉鎖した。
Yahooコメントの仕様が変わった
Yahooも仕様変更を毎年数回してくる。
さすがにメンテナンスだから都度日記にはしてないけど。
Webスクレイピングのサイトを12年間メンテナンスし続けてるが、そろそろ辛い。
何よりアクセス数が一桁/日だし、有限のWeb資源の無駄遣いしてるわ。
SDGs的にも無駄だよね。
で、今回の仕様変更はユーザを特定するURL。
以前は、こんなURLだったのに、
news.yahoo.co.jp/profile/id/YhOfa46Ka2llqZeygvQQQA–/comments
全然別のURLに変わってしまった……。
news.yahoo.co.jp/users/kNBjnynHaIpEZ5XRFicMX2hVvgbpbzg3Kpjb-L3VVlyQnu3b00
理由は分からないけど、2022年11月中旬よりYahooコメント投稿に電話番号が必須になるからかな?
私のサイトの差別化は、12年間のWebスクレイピングにより膨大なユーザーのデータベースを保有していた事。
今回のYahooの仕様変更により、一からユーザ情報を入手必要となってしまった……。
どのように再度ユーザーURLを取得するか?
以前はYahooユーザ名をGoogle検索を使って収集していた。
が、新仕様のYahooユーザ名はGoogleサイト上に一件もヒットしない……。
これもYahooが裏で何かしてるんじゃないの?
仕方ないので、Yahooの記事をクローリングして、コメントしたユーザ名を抽出していく。
Web上をプログラムで巡回すること(巡回してなにかをすること)
で、結局、Seleniumを使うことになった。
Web ブラウザの操作を自動化するためのフレームワーク
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
def get_user_list(self, suffix): """ ユーザURLを入手 :param str url: """ url_list = [] print(_BASE_URL + suffix) self._br.get(_BASE_URL + suffix) html = self._br.page_source # 切り出す p = r'https://news.yahoo.co.jp/articles/(\w+)\"' r = re.findall(p, html) for item in r: print(item) self._br.get('https://news.yahoo.co.jp/articles/' + item + '/comments') html2 = self._br.page_source p2 = r'https://news.yahoo.co.jp/users/(\w+)\"' r2 = re.findall(p2, html2) for item2 in r2: if 'me' not in item2: url_list.append(item2) |
で、各ジャンル毎のニュースに対してコメントしてるユーザを取得してみたら60分かかった。
……長い。
Python+Seleniumで自動実行を行う時に並列で回す
これは備忘録。
今度やってみよう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
from selenium import webdriver from selenium.webdriver import Chrome import concurrent.futures def driverfunc(order): drvpath="C:/mydriverpath/chromedriver.exe" driver = webdriver.Chrome(drvpath) # basic認証の場合はユーザー:パスワード@サイトURLでgetできる driver.get("http://basicuser:basicpass@example.com") # ============================================== # 以下seleniumでの自動処理を記述する。 # ============================================== driver.close() # 並列実行するテストケースの配列 # このサンプルはあくまでも書き方サンプルなのでデータは適当 testcase = [1,2,3,4,5] # 並列実行するexecutorを用意する。 # max_workers が最大の並列実行数 executor = concurrent.futures.ThreadPoolExecutor(max_workers=2) for t in testcase: executor.submit(driverfunc,t) |
おわりに
結局 万単位のユーザ情報をゲットしてたのに1800件だけになっちゃった……。
自身で利用するサービスであれば更新したくなるけど、このランキングは まったく役に立ってない。
単なる技術的な戦い目的で更新してるだけだな。