ナード戦隊データマン

データサイエンスを用いて悪と戦うぞ

スクレイピングのための2つの課題とブラックハット的解決

スクレイピングとは、Web上のコンテンツを自動的に抽出するテクニックの総称です。ここでは、スクレイピング時に生じる2つの技術的問題についてまとめ、「ブラックハット的解決策」を考えていきます。

課題1: 速度が遅い

スクレイピングの一つの課題は、「速度」です。ちまちまと、一つ一つ情報取得していては、いくらCPUが優れていても無意味です。なぜならこれはCPUの問題ではなく、ネットワークの問題だからです。

一般的に、ネットワークの並列的アクセスは、ダウンロード速度を向上させます。しかし、これはDoS攻撃のように、対象サイトへと大量アクセスをすることを意味しています。

ともあれ、速度の問題を一旦解決する単純なコードの例を見てみましょう。

import pymp
import pandas as pd
import diffbot
import json

token = "diffbotのトークンを設定してください"
urls = pd.read_csv("example_urls.csv")['url'].tolist()

with pymp.Parallel(100) as p:
    for index in p.range(0, len(urls)):
        try:
            with open("{}.json".format(index), "w") as f:
                json.dump(diffbot.article(urls[index], token=token), f) 
        except:
            print("ERROR:{}".format(index))

これは、ターゲットのurlリストを用意した上で、そのURLから並列にコンテンツ抽出を実行するコードです。urllistが特定のドメインに限定されている場合、大量アクセスを仕掛けることになります。しかし、速度はとんでもなく向上します。

課題2: アクセスブロックされる

Google検索のスクレイピングは、困難なタスクの一つです。Googleは異常なトラフィックを即座に検出し、ボットをブロックしてしまいます。

トラフィックの検出では、以下の要素が考慮されます:

  1. 単位時間あたりのリクエスト数
  2. 同時アクセス数
  3. 通常のリクエストとの挙動の差 (トラフィックパターン)
  4. HTTP Request Header (UAなど)
  5. Cookie
  6. JavaScript

ブロックされないためには、通常のリクエスト、つまり人間が普通に使うトラフィックと似せる必要があります。

例えば、ヘッドレスブラウザを使うのが一つの方法です。ヘッドレスブラウザを使ったコードの例は以下です:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from random import randrange
import time
import pickle
import pandas as pd

url = "https://example.com/?q={}"
querys = pd.read_csv("queries.csv")['query'].tolist()

options = Options()
options.binary_location = '/usr/bin/chromium-browser'
options.add_argument('--headless')
options.add_argument('--window-size=1280,1024')
options.add_argument('--no-sandbox')

with open("proxylist.pkl", "rb") as f:
    proxies = pickle.load(f)

def build_driver(proxies, options, executable_path)
    proxy = proxies[randrange(0, len(proxies))]
    options.add_argument('--proxy-server=http://%s' % proxy['server'])
    options.add_argument('--proxy-auth=%s' % proxy['auth'])
    return webdriver.Chrome(executable_path=executable_path, chrome_options=options)

results = []
for query in queries:
   driver = build_driver(proxies, options, "chromedriverへのパス")
   driver.get(url.format(query))
   results.append(driver.page_source)
   time.sleep(randrange(10, 20))

ここで、「プロキシリスト」が用いられています。シングルIPの場合、ボットだと検出されやすくなります。一方で、プロキシのIPが150件ぐらい用意されていれば、ボットだと検出されにくくなります。

また、スリープ時間(インターバル)を設定し、ランダムな時間にすれば挙動を人間と区別することが困難になります。スリープ時間が長いほど、ブロックされる可能性が減るので、速度と検出される確率はトレードオフになります。

まとめ

  1. 速度を向上させるにはマルチスレッドが良い。
  2. アクセスブロックを回避するには、1)プロキシリストを使う, 2)ヘッドレスブラウザを使う, 3)インターバルの設定, が有効。