リファレンス
<h2>headline2</h2>
<h3>headline3</h3>
<div class="box">
<ul>
<li>list 1</li>
<li>list 2</li>
<li><span>list 3</span></li>
</ul>
</div>
ソース読み込み
import urllib.request
from bs4 import BeautifulSoup
import pandas as pd
import time
ローカルファイル
soup = BeautifulSoup(open('import.html'), 'html.parser')
公開ウェブページ
# ユーザーエージェント編集
ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) \
AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/90.0.4430.212 Safari/537.36'
req = urllib.request.Request(url, headers={'User-Agent': ua})
html = urllib.request.urlopen(req)
soup = BeautifulSoup(html, "html.parser")
要素の取得
find
系と select
系
- 各種タグの取得には
find
系とselect
系の2種がある - それぞれ記法が異なる場合があるが、
select
系の方が直感的に HTML タグを取得しやすい
Beautiful Soup のfind_all( ) と select( ) の使い方の違い - ガンマソフト株式会社
該当する要素を1つだけ抽出: select_one()
html = '''
<div id="wrapper">
<div class="box">
<ul>
<li><a href="http://localhost:8888/mamp_1">MAMP_1</a></li>
<li><a href="http://localhost:8888/mamp_2">MAMP_2</a></li>
<li><a href="http://localhost:8888/mamp_3">MAMP_3</a></li>
</ul>
</div>
<div class="box">
<ul>
<li><a href="http://localhost:8888/mamp_4">MAMP_4</a></li>
<li><a href="http://localhost:8888/mamp_5">MAMP_5</a></li>
<li><a href="http://localhost:8888/mamp_6">MAMP_6</a></li>
</ul>
</div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
div = soup.select_one('.box')
print((div))
# <div class="box">
# <ul>
# <li><a href="http://localhost:8888/mamp_1">MAMP_1</a></li>
# <li><a href="http://localhost:8888/mamp_2">MAMP_2</a></li>
# <li><a href="http://localhost:8888/mamp_3">MAMP_3</a></li>
# </ul>
# </div>
print(type(div))
# <class 'bs4.element.Tag'>
div = str(soup.select_one('.box'))
print(type(div))
# <class 'str'>
該当する要素をすべて抽出: select()
select()
で要素を取得すると<class 'bs4.element.ResultSet'>
となるが、通常のリストと同じようにアクセスできる。
html = '''
<div id="wrapper">
<div class="box">
<ul>
<li><a href="http://localhost:8888/mamp_1">MAMP_1</a></li>
<li><a href="http://localhost:8888/mamp_2">MAMP_2</a></li>
<li><a href="http://localhost:8888/mamp_3">MAMP_3</a></li>
</ul>
</div>
<div class="box">
<ul>
<li><a href="http://localhost:8888/mamp_4">MAMP_4</a></li>
<li><a href="http://localhost:8888/mamp_5">MAMP_5</a></li>
<li><a href="http://localhost:8888/mamp_6">MAMP_6</a></li>
</ul>
</div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
div = soup.select('.box')
print((div))
# [<div class="box">
# <ul>
# <li><a href="http://localhost:8888/mamp_1">MAMP_1</a></li>
# <li><a href="http://localhost:8888/mamp_2">MAMP_2</a></li>
# <li><a href="http://localhost:8888/mamp_3">MAMP_3</a></li>
# </ul>
# </div>, <div class="box">
# <ul>
# <li><a href="http://localhost:8888/mamp_4">MAMP_4</a></li>
# <li><a href="http://localhost:8888/mamp_5">MAMP_5</a></li>
# <li><a href="http://localhost:8888/mamp_6">MAMP_6</a></li>
# </ul>
# </div>]
print(type(div))
# <class 'bs4.element.ResultSet'>
div = soup.select('.box li')
for d in div:
print(d)
# <li><a href="http://localhost:8888/mamp_1">MAMP_1</a></li>
# <li><a href="http://localhost:8888/mamp_2">MAMP_2</a></li>
# <li><a href="http://localhost:8888/mamp_3">MAMP_3</a></li>
# <li><a href="http://localhost:8888/mamp_4">MAMP_4</a></li>
# <li><a href="http://localhost:8888/mamp_5">MAMP_5</a></li>
# <li><a href="http://localhost:8888/mamp_6">MAMP_6</a></li>
print(type(d))
# <class 'bs4.element.Tag'>
print(type(str(d)))
# <class 'str'>
get_text()
HTMLタグを除去して文字列のみを取得する
string
メソッドは意図しない挙動をすることが多いのでget_text()
に統一した方がよい- BeautifulSoup4のtextで要素の文字列を得る - なるぽのブログ
div = soup.select_one('.box').get_text()
- BeautifulSoup4のtextで要素の文字列を得る - なるぽのブログ
strip()
文字列前後の余計な空白を削除 & 改行を削除
div = soup.select_one('.box').get_text().strip()
None (<class 'NoneType'>)
の扱い
- BeautifulSoup で存在しないタグを取得しようとすると
None
が返る
None
の判定
x = None
print('True') if x is None else print('False')
# True
- 以下のような関数を定義しておくと、エラーを除外しつつ余計な空白や改行を取り除いた文字列のみを取得できる
def select_one_text(soup, elm):
res = soup.select_one(elm)
return res.get_text().strip() if res is not None else None
a タグ
URLを取得
url_list = soup.select('.box a')
print(url_list)
# [<a href="http://localhost:8888/mamp_1">MAMP_1</a>, <a href="http://localhost:8888/mamp_2">MAMP_2</a>, <a href="http://localhost:8888/mamp_3">MAMP_3</a>, <a href="http://localhost:8888/mamp_4">MAMP_4</a>, <a href="http://localhost:8888/mamp_5">MAMP_5</a>, <a href="http://localhost:8888/mamp_6">MAMP_6</a>]
for u in url_list:
url = u.get('href')
print(url)
# http://localhost:8888/mamp_1
# http://localhost:8888/mamp_2
# http://localhost:8888/mamp_3
# http://localhost:8888/mamp_4
# http://localhost:8888/mamp_5
# http://localhost:8888/mamp_6
target_url_list = []
for u in url_list:
url = u.get('href')
url = url.split('?')[0] # URLパラメーター削除
target_url_list.append(url)
print(target_url_list)
# ['http://localhost:8888/mamp_1', 'http://localhost:8888/mamp_2', 'http://localhost:8888/mamp_3', 'http://localhost:8888/mamp_4', 'http://localhost:8888/mamp_5', 'http://localhost:8888/mamp_6']
img タグ
html ='\
<img src="https://sample.jpg" alt="data-src" class="image_src">\
<img data-src="https://sample.jpg" alt="data-src" class="image_data_src">'
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
img_src = soup.select('.image_src')
img_data_src = soup.select('.image_data_src')
for i in img_src:
i = i.get("src")
print(i)
# 画像が'data-src'の場合
for i in img_data_src:
i = i.get("data-src")
print(i)
画像ファイル名を取得
imgs = ['https://hoge.com/img/common/a.png', 'https://hoge.com/img/common/b.png', 'https://hoge.com/img/common/c.jpg', 'https://hoge.com/img/common/d.png', 'https://hoge.com/img/common/e.gif']
for im in imgs:
filename = im.split('/')[-1]
print(filename)
# a.png
# b.png
# c.jpg
# d.png
# e.gif
HTMLタグ内の文字列を取得
txt = soup.select_one('.txtElm').string
前後要素の検索
ユーザーエージェント変更
エラー処理
エラーが起こってもループを止めない
URLリクエスト
from bs4 import BeautifulSoup
import urllib.request
from urllib.error import HTTPError
from urllib.error import URLError
from http.client import RemoteDisconnected
import random
url_list = ['hoge']
user_agent = ['hoge']
for u in url_list:
try:
ua = user_agent[random.randrange(0, len(user_agent), 1)] #ユーザーエージェントをランダムで生成
req = urllib.request.Request(u, headers={'User-Agent': ua})
html = urllib.request.urlopen(req)
soup = BeautifulSoup(html, "html.parser")
# ////////////////////////////////////////////////////////////////////////
except HTTPError as e:
continue
except URLError as e:
continue
except RemoteDisconnected:
continue
スクレイピング
for f in files:
try:
text = soup.select('.text')
content = ''
for t in text:
t = str(t.get_text().strip()) + '\n\n'
content += t
except:
content = ''
NoneType
の条件分岐
found = li.find('a')
if found is not None:
print(found.text)
画像URLから画像ダウンロード
import urllib.error
import urllib.request
fName = 'IMGfile_name'
def download_file(url, dst_path):
try:
with urllib.request.urlopen(url) as web_file:
data = web_file.read()
with open(dst_path, mode='wb') as local_file:
local_file.write(data)
except urllib.error.URLError as e:
print(e)
url = 'https://sample.jpg'
dst_path = 'img/' + fName + '.jpg' # 保存先フォルダとファイル名を指定
download_file(url, dst_path)
画像URLから画像を検証する
- 画像ファイルが gif であったり、大きさが小さいかなどを検証する
- pillowモジュールの
Image.open()
に直接画像 URL を記述しても値を取得できない
import requests
from PIL import Image
import io
img_url = ['https://sample-1.jpg', 'https://sample-2.jpg']
for i in img_url:
img = Image.open(io.BytesIO(requests.get(i).content))
if img.format == 'GIF' or img.size[0] <= 800:
continue
else:
print(img)