スクレイピングを学んでいるときのメモ①~Requests,lxml~
最近スクレイピングを学んでいるのだが、使ったことないライブラリの使用が増えてきたので、使い方のメモを備忘録として残しておく。
ちなみに教材は以下。
増補改訂版もあるので今買うならこっち。
Requestsライブラリ
response = requests.get(url)
上記の使い方で特定のURLのResponseオブジェクトを取得できる。
Responseオブジェクトには以下の属性やメソッドがある。
import requests
response = requests.get('https://gihyo.jp/dp')
print(dir(response))
#結果
['__attrs__', '__bool__', '__class__', '__delattr__', '__dict__',
'__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__',
'__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__iter__', '__le__', '__lt__',
'__module__', '__ne__', '__new__', '__nonzero__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__setstate__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_content',
'_content_consumed', '_next', 'apparent_encoding', 'close', 'connection',
'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history',
'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines',
'json', 'links', 'next', 'ok', 'raise_for_status', 'raw', 'reason',
'request', 'status_code', 'text', 'url']
よく使うものだけ例を示す。
import requests
response = requests.get('https://gihyo.jp/dp')
print(response.status_code)
#200
print(response.headers)
#結果
{'Date': 'Sat, 18 Apr 2020 02:42:02 GMT',
'Content-Type': 'text/html; charset=UTF-8',
'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive',
'Set-Cookie': '__cfduid=d39c02e3e3825eb074c37d122ba4d44ad1587177722; expires=Mon,18-May-20 02:42:02 GMT; path=/; domain=.gihyo.jp; HttpOnly; SameSite=Lax,SN4dc8937382ea6=9-O1fcg30miggMj2On1dwqWEWnc; expires=Sat,18-Apr-2020 04:42:02 GMT; Max-Age=7200; path=/; HttpOnly',
'Vary': 'Accept-Encoding',
'Expires': 'Thu, 19 Nov 1981 08:52:00 GMT',
'Cache-Control': 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0',
'Pragma': 'no-cache',
'X-FRAME-OPTIONS': 'SAMEORIGIN',
'X-XSS-Protection': '1; mode=block',
'Content-Encoding': 'gzip',
'CF-Cache-Status': 'DYNAMIC',
'Expect-CT': 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"',
'Server': 'cloudflare',
'CF-RAY': '585b07be3c14d63d-NRT',
'alt-svc': 'h3-27=":443"; ma=86400, h3-25=":443"; ma=86400, h3-24=":443"; ma=86400, h3-23=":443"; ma=86400',
'cf-request-id': '022cc32adf0000d63d93844200000001'}
status_codeはエラー判定に使えそう。
headersは辞書型のように使えるので、必要な情報を選択して使うのがよさそう。
textはhtmlがstr型で格納されている。
requestsにはSessionクラスがあり、sessionインスタンスでrequestsのgetメソッドと同じようにresponseを得られる。
sessionを使ってリクエストを送るとHTTP Keep-Aliveを使って接続するので、複数のリクエストを送るときはサーバ側の負荷を軽減できる。
import requests
session = requests.Session()
print(session.headers)
#{'User-Agent': 'python-requests/2.22.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
response = session.get('https://gihyo.jp/dp')
print(response.status_code)
print(response.headers)
print(response.text)
lxmlライブラリ
htmlからデータを抜き出す際に用いる。
import lxml.html
import requests
session = requests.Session()
response = session.get('https://gihyo.jp/dp')
html = response.text
print(type(html))
#<class 'str'>
root = lxml.html.fromstring(html)
print(type(root))
#<class 'lxml.html.HtmlElement'>
まず先ほど紹介したsessionを用いた方法でhtmlを取得する。それからlxml.html.fromstring()を使って<class 'lxml.html.HtmlElement'>オブジェクトのhtmlを取得している。
lxml.html.HtmlElementから特定の要素を抜き出すメソッドにはcssselectメソッドとxpathメソッドがある。
ここではcssselectメソッドのみを見ていく。たとえばhtmlのa要素だけを抜き出したいときは下記のように用いる。
import lxml.html
import requests
base_url = 'https://gihyo.jp'
session = requests.Session()
response = session.get(base_url)
html = response.text
root = lxml.html.fromstring(html)
print(type(root.cssselect("a")[0]))
#<class 'lxml.html.HtmlElement'>
lxml.html.HtmlElementオブジェクトとして抜き出せている。この要素に具体的にどのようなものが格納されているかはattribで確認できる。
import lxml.html
import requests
base_url = 'https://gihyo.jp'
session = requests.Session()
response = session.get(base_url)
html = response.text
root = lxml.html.fromstring(html)
for a in root.cssselect("a"):
print(a.attrib)
#結果
{'href': '/'}
{'href': '/site/inquiry'}
{'href': '/site/profile'}
{'href': '/dev', 'title': 'DEVELOPER STAGE'}
{'href': '/admin', 'title': 'ADMINISTRATOR STAGE'}
...
hrefというkeyでbase_urlからの相対urlが格納されていることと、ものによってはtitleというkeyで値が格納されている。上の例にある{'href': '/dev', 'title': 'DEVELOPER STAGE'}が具体的にhtmlのどの部分から抽出しているかを見てみると、以下の部分であることがわかる。
<a href="/dev" title="DEVELOPER STAGE">デベロッパ</a>
この場合、データを抜き出すときは「デベロッパ」も併せて抜き出したい。これはa.textで抜き出すことが出来る。そこで最終的には以下のようなコードにした。
from urllib.parse import urljoin
import lxml.html
import requests
base_url = 'https://gihyo.jp'
session = requests.Session()
response = session.get(base_url)
html = response.text
root = lxml.html.fromstring(html)
for a in root.cssselect("a"):
print(urljoin(base_url,a.get("href")),a.get("title"),a.text)
#結果
https://gihyo.jp/ None None
https://gihyo.jp/site/inquiry None お問い合わせ
https://gihyo.jp/site/profile None 会社案内
https://gihyo.jp/dev DEVELOPER STAGE デベロッパ
https://gihyo.jp/admin ADMINISTRATOR STAGE アドミニストレータ
...
先ほど確認したようにaは実質dict型なので、get()でvalueを取得できる。
また、urlは相対パスだと不便なので絶対パスに変換しておく。
この記事が気に入ったらサポートをしてみませんか?