【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.2】

今回は Python 3.6 & Selenium WebDriver & headless でスクレイピングの2回目です。

普段はインフラ系エンジニアとして現場で業務をしていますが、更にステップアップするためにプログラミングスキルもコツコツと身に付けていこうと考えています。

 

 

【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.1】

 

【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.2】

 

【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.3】

 

【Python】Python 3.6 & Selenium WebDriver & PhantomJS でスクレイピング(find系操作)【Part.4】

 

【Python】Python 3.6 & Selenium WebDriver & PhantomJS でスクレイピング(URLを引数で受け取る)【Part.5】

 

 

 

仮想環境への切り替え

仮想環境に切り替えます。(仮想環境の有効化)

[test@SAKURA_VPS pyenv]$ source pyenv/bin/activate
(pyenv) [test@SAKURA_VPS pyenv]$ ← 仮想環境になりました。

 

ただ、思ったのがわざわざ仮想環境に切り替える必要があるのかどうか。

というのも、別途 Python3.6 をインストール済みだからです。

 

 

一番シンプルなプログラム

一番シンプルなプログラムです。

何をやってもエラーが出てどうしようもなくなったら、一旦ここに帰ります。

ただしヤフーは表示されるが、他のサイトは拒否られることが多いです。

from selenium import webdriver

url = 'https://yahoo.co.jp/'
driver = webdriver.PhantomJS()
driver.get(url)

print(driver.page_source)

 

 

実行例です。

(pyenv) [test@SAKURA_VPS scraping]$ python test_selenium.py
<html lang="ja">

<link rel="icon" sizes="any" mask="" href="//s.yimg.jp/l/cmn/svi/y.svg">
<meta name="theme-color" content="#FF0033">
<link rel="alternate icon" type="image/x-icon" href="/favicon.ico">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="content-style-type" content="text/css">
<meta http-equiv="content-script-type" content="text/javascript">
<meta name="description" content="日本最大級のポータルサイト。検索、オークション、ニュース、天気、スポーツ、メール、ショッピングなど多数のサービスを展開。あなたの生活をより豊かにする「課題解決エンジン」を目指していきます。">
<meta name="robots" content="noodp">
<meta name="google-site-verification" content="fsLMOiigp5fIpCDMEVodQnQC7jIY1K3UXW5QkQcBmVs">
<link rel="alternate" href="android-app://jp.co.yahoo.android.yjtop/yahoojapan/home/top">
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://m.yahoo.co.jp/">
<link rel="canonical" href="https://www.yahoo.co.jp/">
<meta property="og:title" content="Yahoo! JAPAN"><meta property="og:type" content="article"><meta property="og:url" content="https://www.yahoo.co.jp/"><meta property="og:image" content="https://s.yimg.jp/images/top/ogp/fb_y_1500px.png"><meta property="og:description" content="日本最大級のポータルサイト。検索、 オークション、ニュース、天気、スポーツ、メール、ショッピングなど多数のサービスを展開。あなたの生活をより豊かにする「課題解決エンジン」を目指していきます。"><meta property="og:site_name" content="Yahoo! JAPAN"><meta property="twitter:card" content="summary_large_image"><meta property="twitter:site" content="@Yahoo_JAPAN_PR"><meta property="twitter:title" content="Yahoo! JAPAN"><meta property="twitter:description" content="日本最大級のポータルサイト。検索、オークション、ニュース、天気、スポーツ、メール、ショッピング など多数のサービスを展開。あなたの生活をより豊かにする「課題解決エンジン」を目指していきます。"><meta property="twitter:image" content="https://s.yimg.jp/images/top/ogp/tw_y_1400px.png"><meta property="fb:app_id" content="472870002762883">Yahoo! JAPAN
<style type="text/css"><!--

 

Selenium で User Agent を設定する

サイトによっては User Agent がないとはじかれます。

そのため User Agent を設定します。

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

 

# Wikiのメインページにアクセス
url = 'https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8'

dcap = dict(DesiredCapabilities.PHANTOMJS)
dcap["phantomjs.page.settings.userAgent"] = (
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/53 "
    "(KHTML, like Gecko) Chrome/15.0.87"
)
driver = webdriver.PhantomJS(desired_capabilities=dcap)
driver.get(url)
print(driver.page_source)

 

 

実行結果です。

(pyenv) [test@SAKURA_VPS scraping]$ python test_selenium.py
<!DOCTYPE html><html class="client-js ve-not-available" lang="ja" dir="ltr"><head>
<meta charset="UTF-8">
<title>Wikipedia</title>
<script>document.documentElement.className = document.documentElement.className.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );</script>
<script>(window.RLQ=window.RLQ||[]).push(function(){mw.config.set({"wgCanonicalNamespace":"","wgCanonicalSpecialPageName":false,"wgNamespaceNumber":0,"wgPageName":"メインページ","wgTitle":"メインページ","wgCurRevisionId":65264604,"wgRevisionId":65264604,"wgArticleId":253348,"wgIsArticle":true,"wgIsRedirect":false,"wgAction":"view","wgUserName":null,"wgUserGroups":["*"],"wgCategories":[],"wgBreakFrames":false,"wgPageContentLanguage":"ja","wgPageContentModel":"wikitext","wgSeparatorTransformTable":["",""],"wgDigitTransformTable":["",""],"wgDefaultDateFormat":"ja","wgMonthNames":["","1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],"wgMonthNamesShort":["","1月","2 月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],"wgRelevantPageName":"メインページ","wgRelevantArticleId":253348,"wgRequestId":"WhW0ZApAAEEAAFSiTB0AAACT","wgIsProbablyEditable":false,"wgRelevantPageIsProbablyEditable":false,"wgRestrictionEdit":["sysop"],"wgRestrictionMove":["sysop"],"wgIsMainPage":true,"wgWikiEditorEnabledModules":{"toolbar":true,"preview":false,"publish":false},"wgBetaFeaturesFeatures":[],"wgMediaViewerOnClick":true,"wgMediaViewerEnabledByDefault":true,"wgPopupsShouldSendModuleToUser":true,"wgPopupsConflictsWithNavPopupGadget":false,"wgVisualEditor":{"pageLanguageCode":"ja","pageLanguageDir":"ltr","pageVariantFallbacks":"ja","usePageImages":true,"usePageDescriptions":true},"wgPreferredVariant":"ja","wgMFExpandAllSectionsUserOption":false,"wgMFDisplayWikibaseDescriptions":{"search":true,"nearby":true,"watchlist":true,"tagline":true},"wgRelatedArticles":null,"wgRelatedArticlesUseCirrusSearch":true,"wgRelatedArticlesOnlyUseCirrusSearch":false,"wgULSCurrentAutonym":"日本語","wgNoticeProject":"wikipedia","wgCentralNoticeCookiesToDelete":[],"wgCentralNoticeCategoriesUsingLegacy":["Fundraising","fundraising"],"wgCategoryTreePageCategoryOptions":"{\"mode\":0,\"hideprefix\":20,\"showcount\":true,\"namespaces\":false}","wgWikibaseItemId":"Q5296","wgCentralAuthMobileDomain":false,"wgCodeMirrorEnabled":false,"wgVisualEditorToolbarScrollOffset":0,"wgVisualEditorUnsupportedEditParams":["undo","undoafter","veswitched"],"wgEditSubmitButtonLabelPublish":true});mw.loader.state({"ext.globalCssJs.user.styles":"ready","ext.globalCssJs.site.styles":"ready","site.styles":"ready","noscript":"ready","user.styles":"ready","user":"ready","user.options":"loading","user.tokens":"loading","ext.cite.styles":"ready","ext.categoryTree.css":"ready","ext.visualEditor.desktopArticleTarget.noscript":"ready","ext.uls.interlanguage":"ready","ext.wikimediaBadges":"ready","mediawiki.legacy.shared":"ready","mediawiki.legacy.commonPrint":"ready","mediawiki.sectionAnchor":"ready","mediawiki.skinning.interface":"ready","skins.vector.styles":"ready","ext.globalCssJs.user":"ready","ext.globalCssJs.site":"ready"});mw.loader.implement("user.options@0sbylvi",function($,jQuery,require,module){mw.user.options.set({"variant":"ja"});});mw.loader.implement("user.tokens@1dqfd7l",function ( $, jQuery, require, module ) {

 

 

本当に設定したユーザーエージェントでアクセスしているか確認

疑問に思ったことが、そもそも本当にこのユーザーエージェントでサイトにアクセスをしているのかどうかということです。

 

tcpdumpコマンドでパケットをキャプチャしながら、スクレイピングをしてパケットの中身を解析します。

rootアカウントにスイッチして(tcpdumpは一般アカウントでは取得できない)、80番ポートだけ絞ってパケットをキャプチャします。

[root@SAKURA_VPS ~]# tcpdump port 80 -i eth0 -w test111.cap
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
^C4100 packets captured
6202 packets received by filter
2102 packets dropped by kernel
[root@SAKURA_VPS ~]#

 

キャプチャ結果を出力したファイル「test111.cap」をローカルのパソコンに持ってきて、Wiresharkで解析をします。

確かに「"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/53 " "(KHTML, like Gecko) Chrome/15.0.87"」の文字列があるので、指定したユーザーエージェントでアクセスをしているようです。

 

念のため、ユーザーエージェントの文字列を変更してみます。

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

url = 'http://www.metro.tokyo.jp/'

dcap = dict(DesiredCapabilities.PHANTOMJS)
dcap["phantomjs.page.settings.userAgent"] = (
    "Mozilla/1111115.0 (X11; Linux x86_64) AppleWebKit/111111153 " ← 変更
    "(KHTML, like Gecko) test Chrome/15.0.871111111111111"     ← 変更
)
driver = webdriver.PhantomJS(desired_capabilities=dcap)
driver.get(url)
print(driver.page_source)

 

 

再度 tcpdump をしながらプログラムを実行します。

[root@SAKURA_VPS ~]# tcpdump port 80 -i eth0 -w test11111.cap
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
^C3937 packets captured
6128 packets received by filter
2191 packets dropped by kernel
[root@SAKURA_VPS ~]#

 

パケットの中身を見ると確かにユーザーエージェントは書き変わっています。

 

 

DesiredCapabilitiesとは

DesiredCapabilitiesでユーザーエージェントを指定していますが、DesiredCapabilitiesを利用することで

  • ブラウザの種類(Firefox、Google Chromeなど)
  • ブラウザのオプション
  • ブラウザのバージョン
  • ユーザーエージェント

など様々な設定をすることが可能です。

 

 

Python 辞書型

  • {}で囲む
  • keyとvalue(キーと値)の組み合わせ
  • keyとvalueは「:(コロン)」で区切る
  • keyとvalueのセットは、「,(カンマ)」で区切る

 

サンプルプログラム

(pyenv) [test@SAKURA_VPS scraping]$ vi test_dict.py

test = {'NHK':1,'日テレ':4,'テレビ朝日':5,'TBS':6,'テレビ東京':7,'フジテレビ':8}

 

print(test)
print(test['NHK'])
print(test['日テレ'])
print(test['テレビ朝日'])
print(test['テレビ東京'])

 

 

プログラムを実行します。

(pyenv) [test@SAKURA_VPS scraping]$ python test_dict.py
{'NHK': 1, '日テレ': 4, 'テレビ朝日': 5, 'TBS': 6, 'テレビ東京': 7, 'フジテレビ': 8}
1
4
5
7
(pyenv) [test@SAKURA_VPS scraping]$

 

 

Firefox を使用した際の「No such file or directory: 'geckodriver': 'geckodriver'」のエラー出力

geckodriverがインストールされていないと以下のような「FileNotFoundError: [Errno 2] No such file or directory: 'geckodriver': 'geckodriver'が出力されます。

(pyenv) [test@SAKURA_VPS scraping]$ python test_selenium.py
Traceback (most recent call last):
  File "/home/test/pyenv/lib64/python3.6/site-packages/selenium/webdriver/common/service.py", line 74, in start
    stdout=self.log_file, stderr=self.log_file)
  File "/usr/lib64/python3.6/subprocess.py", line 709, in __init__
    restore_signals, start_new_session)
  File "/usr/lib64/python3.6/subprocess.py", line 1344, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'geckodriver': 'geckodriver'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test_selenium.py", line 4, in 
    browser = Firefox()
  File "/home/test/pyenv/lib64/python3.6/site-packages/selenium/webdriver/firefox/webdriver.py", line 144, in __init__
    self.service.start()
  File "/home/test/pyenv/lib64/python3.6/site-packages/selenium/webdriver/common/service.py", line 81, in start
    os.path.basename(self.path), self.start_error_message)
selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs to be in PATH.

(pyenv) [test@SAKURA_VPS scraping]$

 

Selenium はインタフェースとしてのブラウザのドライバを必要とします。

例えば、Firefox の場合は「geckodriver」ドライバを必要とします。

 

【例】

Firefoxの場合

https://github.com/mozilla/geckodriver/releases

 

「geckodriver-v0.19.1-linux64.tar.gz」をダウンロードします。

(pyenv) [test@SAKURA_VPS ~]$ wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz
--2017-11-23 00:34:58--  https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz
github.com (github.com) をDNSに問いあわせています... 192.30.255.112, 192.30.255.113
github.com (github.com)|192.30.255.112|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 302 Found
場所: https://github-production-release-asset-2e65be.s3.amazonaws.com/25354393/e31e4c22-be6f-11e7-9bc7-dedc3490a7fd?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20171122%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20171122T153458Z&X-Amz-Expires=300&X-Amz-Signature=baa732b1a15f4a37be0641185287f13969c8c56d2b18d4ea476a7a185339f6a9&X-Amz-SignedHeaders=host&actor_id=0&response-content-disposition=attachment%3B%20filename%3Dgeckodriver-v0.19.1-linux64.tar.gz&response-content-type=application%2Foctet-stream [続く]
--2017-11-23 00:34:58--  https://github-production-release-asset-2e65be.s3.amazonaws.com/25354393/e31e4c22-be6f-11e7-9bc7-dedc3490a7fd?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20171122%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20171122T153458Z&X-Amz-Expires=300&X-Amz-Signature=baa732b1a15f4a37be0641185287f13969c8c56d2b18d4ea476a7a185339f6a9&X-Amz-SignedHeaders=host&actor_id=0&response-content-disposition=attachment%3B%20filename%3Dgeckodriver-v0.19.1-linux64.tar.gz&response-content-type=application%2Foctet-stream
github-production-release-asset-2e65be.s3.amazonaws.com (github-production-release-asset-2e65be.s3.amazonaws.com) をDNSに問いあわせています... 54.231.49.72
github-production-release-asset-2e65be.s3.amazonaws.com (github-production-release-asset-2e65be.s3.amazonaws.com)|54.231.49.72|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 2301226 (2.2M) [application/octet-stream]
`geckodriver-v0.19.1-linux64.tar.gz' に保存中

100%[==============================================================>] 2,301,226   1.24MB/s 時間 1.8s

2017-11-23 00:35:01 (1.24 MB/s) - `geckodriver-v0.19.1-linux64.tar.gz' へ保存完了 [2301226/2301226]

(pyenv) [test@SAKURA_VPS ~]$

 

 

ダウンロードした「geckodriver-v0.19.1-linux64.tar.gz」を展開して「/usr/local/bin」にコピーします。

(pyenv) [test@SAKURA_VPS ~]$ tar xvfz geckodriver-v0.19.1-linux64.tar.gz
geckodriver
(pyenv) [test@SAKURA_VPS ~]$ sudo cp -ip geckodriver /usr/local/bin/
(pyenv) [test@SAKURA_VPS ~]$ ls -l /usr/local/bin/geckodriver
-rwxrwxr-x 1 test test 7194178 11月  1 04:15 /usr/local/bin/geckodriver
(pyenv) [test@SAKURA_VPS ~]$

 

 

 

firefoxのプロセスをまとめてkillする

何度かデバッグを繰り返していると以下のように終了しないfirefoxのプロセスが溜まります。

(pyenv) [test@SAKURA_VPS scraping]$ ps -ef | grep firefox
test      4357     1  0 00:41 pts/2    00:01:13 /usr/lib64/firefox/firefox -marionette -profile /tmp/rust_mozprofile.JWEO0B0JEMzx
test      4458  4357  0 00:41 pts/2    00:03:20 /usr/lib64/firefox/plugin-container -greomni /usr/lib64 firefox/omni.ja -appomni /usr/lib64/firefox/browser/omni.ja -appdir /usr/lib64/firefox/browser 4357 tab
test      4857     1  0 00:48 pts/2    00:00:58 /usr/lib64/firefox/firefox -marionette -profile /tmp/rust_mozprofile.qxESEd4ArZRq
test      4959  4857  0 00:48 pts/2    00:00:02 /usr/lib64/firefox/plugin-container -greomni /usr/lib64 firefox/omni.ja -appomni /usr/lib64/firefox/browser/omni.ja -appdir /usr/lib64/firefox/browser 4857 tab
test     11339  4564  0 07:29 pts/4    00:00:00 grep --color=auto firefox
(pyenv) [test@SAKURA_VPS scraping]$

 

まとめてプロセスを kill するためには pgrep でプロセスを検索して、xargs で kill コマンドを実行して kill します。

(pyenv) [test@SAKURA_VPS scraping]$ pgrep firefox | xargs kill -9
(pyenv) [test@SAKURA_VPS scraping]$ ps -ef | grep firefox
test     11424  4564  0 07:34 pts/4    00:00:00 grep --color=auto firefox
(pyenv) [test@SAKURA_VPS scraping]$

 

 

 

現在勉強している本

Seleniumでどうすればいいのか分からなくなった時に読む本です。

サンプルプログラムは Java で書かれていますが、オプションや構文などは Python でも役に立ちます。

実践 Selenium WebDriver 

 

 

Pythonでどうやって Web スクレイピングをすればいいのか参考になる本です。こちらもどうすればいいのか迷った時に読む本です。

PythonによるWebスクレイピング

 

 

シリーズ一覧

【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.1】

 

【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.2】

 

【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.3】

 

【Python】Python 3.6 & Selenium WebDriver & PhantomJS でスクレイピング(find系操作)【Part.4】

 

【Python】Python 3.6 & Selenium WebDriver & PhantomJS でスクレイピング(URLを引数で受け取る)【Part.5】

 

 

まとめ

全くまとまりのない記事になってしまいましたが、コツコツとノウハウを貯めていきます。

まだまだ先は長くなりそうです。

 

 

Posted by 100%レンタルサーバーを使いこなすサイト管理人

コメントを残す

メールアドレスが公開されることはありません。