SeleniumはBOTだとバレている
Seleniumやpupeteer始めとしたブラウザの自動操縦ライブラリはたくさんありますが、
大手CDNを利用しているサイトやスクレイピング対策を頑張っているサイトだと簡単に
アクセスが拒否されてしまいます。
Google Chromeでは
chromeのDevTools上で
navigator.webdriver;
を実行してみてください。
webdriver
で実行しているわけではないのでfalse
が返ってきます。
Seleniumでは
今度はSeleniumで同じ値を見てみましょう。以下を実行すると
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://www.google.com/')
is_driver = driver.execute_script("return navigator.webdriver;")
print(is_driver)
driver.quit()
true
が出力されます。botだとバレています。
pychromeを使う
先の例から、普段使っているGoogle Chromeを操作できれば良さそうなので、
pychromeというPythonプログラミングからChromeを操作するライブラリを使います。
Google Chromeを起動する
pychromeを使うにはdebugging-portを指定してChromeを起動しておく必要があります。
linuxの場合
google-chrome --headless --disable-gpu --remote-debugging-port=9222 --no-sandbox
macOSの場合
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --disable-gpu --remote-debugging-port=9222 --no-sandbox
とする必要があります。
注意
headlessモードで起動した場合、UserAgentに
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/99.0.4844.51 Safari/537.36
Headless
の文字が含まれています。厳し目のサイトではここの値をチェックされ得るので注意が必要です。
Chromeの起動時に安全なUserAgentを指定して上げましょう。
google-chrome --user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36" --headless --disable-gpu --no-sandbox
--blink-settings=imagesEnabled=false
オプションもおすすめです。
画像の読み込みがなくなるため、ページの読み込みがかなり速くなります。
スクリーンショットを取りたい場合以外は積極的に使いたいです。
サンプルプログラム
適当なURLにアクセスしてHTMLの取得と、画面をPDFとして出力して見ます。
debugging-portを指定してChromeが起動されている必要があります。
import sys
import time
import base64
import pychrome
browser = pychrome.Browser(url="http://127.0.0.1:9222")
tab = browser.new_tab()
tab.start()
tab.Network.enable()
url = 'https://www.youtube.com/'
try:
tab.Page.navigate(url=url, _timeout=7)
except pychrome.exceptions.TimeoutException as e:
print(e)
sys.exit()
# javascriptが以下のように実行できます
time.sleep(1)
res = tab.Runtime.evaluate(expression='document.querySelector("html").outerHTML;')
html = res['result']['value']
# pdf出力
pdf_content = tab.Page.printToPDF()
with open('sample.pdf', 'wb') as f:
data = pdf_content['data']
f.write(base64.b64decode(data))