Python/Beautiful Soupでスクレイピングする方法~Requests編~

Requestsでスクレイピング Python

pythonでrequestsを使ったスクレイピングについて説明する。

スクレイピングとはなんぞや、requestsってなんじゃ、という人は以下を参照されたし。

【Python】自動化:Beautiful Soupでスクレイピングする方法
Webスクレイピングとはなんぞやwebスクレイピングとは、webサイトの情報を抽出するソフトウェア技術のこと。普通はChrome立ち上げて、何かしらで検索して、知りたいこと書いてあるサイトにアクセスして、情報を読み込む.....

上記繰り返しになるが、スクレイピングを行う際は自己責任でどうぞ。

GETリクエスト

公式ドキュメントはコチラ。ただなんていうかね、見づらい…

Requests: 人間のためのHTTP — requests-docs-ja 1.0.4 documentation

ここでは、これ知っていれば大概なんとかなるしょ、っていうものについて記載する。

ヤホーのtopページのhtml取得を例にあげる。

import requests
from bs4 import BeautifulSoup
import re

# 定義
url_get = "https://news.yahoo.co.jp/"
timeout = (3.0, 7.5)

# getリクエストを送信しresオブジェクトにレスポンスを格納
res = requests.get(url_get, timeout=timeout)

# resオブジェクトのテキスト部をbeautiful soupでhtmlパースする
soup = BeautifulSoup(res.text, "html.parser")

# title(タグ付き)を抽出する
title_tag = soup.find("title")
print("title_tag: \n", title_tag, "\n")

# title(テキスト)を抽出する
title = soup.find("title").string
print("title: \n", title, "\n")

# 主要ニュースのliタグをすべて取得する
main_news_tag = soup.find_all("li", class_="topicsListItem")
print("main_news_tag: \n", main_news_tag, "\n")

# 主要ニュースの一覧を取得する
main_news = soup.find_all(href=re.compile("https://news.yahoo.co.jp/pickup/"))
print("title: \n")
for loop in main_news:
    print(loop.getText())

出力結果がこちら。

title_tag: 
 <title data-reactroot="">Yahoo!ニュース</title>

title: 
 Yahoo!ニュース

main_news_tag: 
 [<li class="topicsListItem ・・・長すぎるので省略
] 

title:
陛下 ローマ教皇と笑顔で握手
保護の茨城少女 学校に悩み?
ティファニー1.7兆円買収合意
羊1.4万匹積んだ船転覆 黒海
マツダは運悪い?副社長に聞く
WBC会長 ランクからネリ外す
イモト結婚発表 石崎Dが演出
S・ゴメス 生歌にファン酷評
マツダは運悪い?副社長に聞く

適当に解説。

res = requests.get(url_get, timeout=timeout)

ここでgetリクエストを送信し、resオブジェクトにレスポンスを格納している。実質1行で実行できる。便利。

ここで、timeoutの値は設定しておいた方がいい。設定しない場合、サーバ側からのレスポンスがないとプログラムがフリーズしてしまう。

timeoutはconnect timeoutとread timeoutで構成されている。

  • connect timeout:サーバと接続を確立するまでの待機時間
  • read timeout:サーバがレスポンスを返してくるまでの待機時間

当然ながらread timeoutの方が長い時間を設定しておいた方がいい。重たいページを取得するならもっと長くてもいいだろう。

soup = BeautifulSoup(res.text, "html.parser")

ここでbeautiful soupでhtml構造を解釈させてsoupオブジェクトに格納する。

# title(タグ付き)を抽出する
title_tag = soup.find("title")

# title(テキスト)を抽出する
title = soup.find("title").string

stringをつけると文字列を取得する。実際にはタグ全体ではなくて文字列がほしい場合がほとんどだと思う。

title_tag = soup.find("title")
main_news_tag = soup.find_all("li", class_="topicsListItem")

html内のタグの取得方法は大きく上記2つだ。find()は最初にマッチしたタグ、find_all()はマッチするすべてのタグを取得する。パラメータとして、タグのほかに属性の値を指定できる。

注意が必要なのが、”class”の文字列はpythonの予約語なのでここで指定するときは”class_”にする必要がある。

main_news = soup.find_all(href=re.compile("https://news.yahoo.co.jp/pickup/"))

reパッケージと組み合わせて正規表現で値をとれば大概どんな値も取得できる。

POSTリクエスト

import requests
from bs4 import BeautifulSoup

# 定義
url_login = "https://login.yahoo.co.jp/config/login"
login_info = {
    "login": "あなたのアカウント",
    "passwd": "あなたのパスワード"
}

# postリクエストを送信しresオブジェクトにレスポンスを格納
res = requests.post(url_login, data=login_info, timeout=timeout)

# resオブジェクトをbeautiful soupでhtmlパースする
soup = BeautifulSoup(res.text, "html.parser")

# title(テキスト)を抽出する
title = soup.find("title").string
print("title: \n", title, "\n")

requests.postでリクエストを送信する。

パラメータ”data”にpostデータ部を指定する。

おまけ

取得したいタグ名が分からないとき

chromeの開発ツール(F12)を見たまえ

postデータ部が分からないとき

chromeの開発ツール(F12)を見たまえ

UAを指定する

なにもしないと、requestsを使ったリクエストのユーザーエージェントにはpythonがつくるUAが指定される。

サイトによっては不正アクセス防止策として、UAが怪しいものを遮断しているときがある。念のためchromeなどのあり来たりなUAにしておいた方がいい。

res = requests.post(url_login, data=login_info, headers={"User-Agent": "指定したいUA"}, timeout=timeout)

セッションを維持したいとき

ログインを必要とするサイトに対してスクレイピングしたい場合、セッションが切れる度に都度ログインする必要があり煩わしい。

Requestsはセッションモードなるものがあるので、これを使う。

from requests import Session

# セッション
session: Session = requests.session()

# セッションを維持したままpostリクエスト
res = session.post(url_login, data=login_info, headers={"User-Agent": "指定したいUA"}, timeout=timeout)

javascriptで動的に書き変わる値を取得したいとき

chromeの開発ツールを使って取得したい値が分かっていても、それがjavascriptで動的に書き換わる値である場合、requestsでは太刀打ちできない。

javascriptがブラウザ上で実行されるためだ。

そんなときはブラウザを操作できるseleniumを使うといい。

Python/Beautiful Soupでスクレイピングする方法~Selenium編~
pythonでseleniumを使ったスクレイピングについて説明する。スクレイピングとはなんぞや、 seleniumってなんじゃ、という人は以下を参照されたし。 上記繰り返しになるが、スクレイピングを行う際は自己責...

コメント