web-dev-qa-db-ja.com

Python Seleniumマルチプロセッシング

pythonとSeleniumと組み合わせて、ランディングページからさまざまな投稿のリンクをスクレイプし、最終的に内部ページにつながるURLを追跡して各投稿のタイトルを取得するスクリプトを作成しました。ここで解析したコンテンツは静的なものですが、Seleniumを使用して、マルチプロセッシングでの動作を確認しました。

ただし、私の意図はマルチプロセッシングを使用してスクレイピングを行うことです。これまでのところ、Seleniumはマルチプロセッシングをサポートしていませんが、間違っているようです。

私の質問:マルチプロセッシングを使用して実行する場合、Seleniumを使用して実行時間を短縮するにはどうすればよいですか?

This is my try (it's a working one)

import requests
from urllib.parse import urljoin
from multiprocessing.pool import ThreadPool
from bs4 import BeautifulSoup
from Selenium import webdriver

def get_links(link):
  res = requests.get(link)
  soup = BeautifulSoup(res.text,"lxml")
  titles = [urljoin(url,items.get("href")) for items in soup.select(".summary .question-hyperlink")]
  return titles

def get_title(url):
  chromeOptions = webdriver.ChromeOptions()
  chromeOptions.add_argument("--headless")
  driver = webdriver.Chrome(chrome_options=chromeOptions)
  driver.get(url)
  sauce = BeautifulSoup(driver.page_source,"lxml")
  item = sauce.select_one("h1 a").text
  print(item)

if __name__ == '__main__':
  url = "https://stackoverflow.com/questions/tagged/web-scraping"
  ThreadPool(5).map(get_title,get_links(url))
16
robots.txt

マルチプロセッシングを使用して実行する場合、Seleniumを使用して実行時間を短縮するにはどうすればよいですか

ソリューションで多くの時間が、各URLのWebドライバーの起動に費やされます。スレッドごとに1回だけドライバーを起動することにより、この時間を短縮できます。

(... skipped for brevity ...)

threadLocal = threading.local()

def get_driver():
  driver = getattr(threadLocal, 'driver', None)
  if driver is None:
    chromeOptions = webdriver.ChromeOptions()
    chromeOptions.add_argument("--headless")
    driver = webdriver.Chrome(chrome_options=chromeOptions)
    setattr(threadLocal, 'driver', driver)
  return driver


def get_title(url):
  driver = get_driver()
  driver.get(url)
  (...)

(...)

私のシステムでは、これにより時間は1分7秒から24.895秒に短縮され、約35%改善されます。自分自身をテストするには、 full script をダウンロードしてください。

注:ThreadPoolは、Python GILによって制約されるスレッドを使用します。ほとんどの場合、タスクがI/Oバウンドであれば問題ありません。後処理に応じてスクレイピングされた結果を使用して、multiprocessing.Pool代わりに。これにより、グループとしてGILの制約を受けない並列プロセスが起動します。残りのコードは同じままです。

9
miraculixx

私の質問:どうすれば実行時間を短縮できますか?

SeleniumはWebスクレイピングの間違ったツールのようです。特に、Webサイトとのユーザーインタラクションをシミュレートする必要がある場合、またはJavaScriptの制限/要件がある場合はYMMVを高く評価しています。

あまりやり取りせずにタスクをスクレイピングするために、オープンソース Scrapy Python大規模なスクレイピングタスク用のパッケージ。新しいスクリプトを記述してデータをファイルまたはデータベースに保存するのは簡単です-そしてそれは本当にfastです。

完全に並列なScrapyスパイダーとして実装された場合、スクリプトは次のようになります(これはテストしていません。 セレクターのドキュメント を参照してください)。

import scrapy
class BlogSpider(scrapy.Spider):
    name = 'blogspider'
    start_urls = ['https://stackoverflow.com/questions/tagged/web-scraping']

    def parse(self, response):
        for title in response.css('.summary .question-hyperlink'):
            yield title.get('href')

実行するには、これをblogspider.pyおよび実行

$ scrapy runspider blogspider.py

完全なチュートリアルについては、 Scrapy Webサイト を参照してください。

@SIMのポインターのおかげで、Scrapyは scrapy-splash を介してJavaScriptもサポートしていることに注意してください。私はこれまで何の経験もありませんでしたので、スクレイピーの仕組みとうまく統合されているように見える以外、これについて話すことはできません。

4
miraculixx