スクレイピングの基本を勉強するにはいいかも
今まで見た本の中で説明が長いのと表になっていないので見づらい
Pythonスクレイピングの基本と実践 データサイエンティストのためのWebデータ収集術 (impress top gear)
- 作者: Seppe vanden Broucke,Bart Baesens,株式会社トップスタジオ
- 出版社/メーカー: インプレス
- 発売日: 2018/12/17
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
スクレイピングの基本を勉強するにはいいかも
今まで見た本の中で説明が長いのと表になっていないので見づらい
Pythonスクレイピングの基本と実践 データサイエンティストのためのWebデータ収集術 (impress top gear)
Camelot: PDF Table Extraction for Humans — Camelot 0.8.2 documentation
Installation of dependencies — Camelot 0.8.2 documentation
apt install python3-tk ghostscript pip install camelot-py[cv]
# PATH追加 export PATH=$PATH:/home/imabari/.local/bin # 変換 camelot -p 2-end -o black.xlsx -f excel -split lattice 180928.pdf # 表示 camelot -p 2 lattice -plot joint 180928.pdf # 線が短い表の場合 -scale 40 を付ける camelot -p all -o black.xlsx -f excel -split lattice -scale 40 180928.pdf # テキストの改行スペース削除 -strip ' \n' camelot -p all -o black.xlsx -f excel -split -strip ' \n' lattice 180928.pdf # テキストコピー camelot -p all -o data.csv -f csv -strip ' .\n' -split lattice -scale 40 -copy v data.pdf
Command-Line Interface — Camelot 0.8.2 documentation
Usage: camelot [OPTIONS] COMMAND [ARGS]... Camelot: PDF Table Extraction for Humans Options: --version Show the version and exit. -q, --quiet TEXT Suppress logs and warnings. -p, --pages TEXT Comma-separated page numbers. Example: 1,3,4 or 1,4-end. -pw, --password TEXT Password for decryption. -o, --output TEXT Output file path. -f, --format [csv|json|excel|html] Output file format. -z, --zip Create ZIP archive. -split, --split_text Split text that spans across multiple cells. -flag, --flag_size Flag text based on font size. Useful to detect super/subscripts. -strip, --strip_text TEXT Characters that should be stripped from a string before assigning it to a cell. -M, --margins <FLOAT FLOAT FLOAT>... PDFMiner char_margin, line_margin and word_margin. --help Show this message and exit. Commands: lattice Use lines between text to parse the table. stream Use spaces between text to parse the table.
前回tabulaのは失敗するのでcamelotで再挑戦
Camelot: PDF Table Extraction for Humans — Camelot 0.7.3 documentation
厚生労働省の長時間労働削減に向けた取り組みから www.mhlw.go.jp
労働基準関係法令違反に係る公表事案をダウンロード https://www.mhlw.go.jp/kinkyu/dl/180928.pdf
表の部分しか取れないので労働局名と最新更新日がありません
apt install ghostscript pip install camelot-py[cv]
import re import pandas as pd import matplotlib.pyplot as plt import camelot # 2ページ目から最終頁まで、セパレーター優先、改行除去 tables = camelot.read_pdf('180928.pdf', pages='2-end', split_text=True, strip_text='\n') dfs = [] # dataframeに変換、ヘッダー部削除、ヘッダー追加 for table in tables: df = table.df df.drop(0, inplace=True) df.columns = ['企業・事業場名称', '所在地', '公表日', '違反法条', '事案概要', 'その他参考事項'] dfs.append(df) # ページ結合 df_black = pd.concat(dfs) # カンマを追加 def ihan_conv(temp): result = re.sub('条(の\d{1,3})?', lambda m: m.group(0) + ', ', temp).rstrip(', ') return result def sonota_conv(temp): result = re.sub('H\d{1,2}\.\d{1,2}\.\d{1,2}', lambda m: ', ' + m.group(0), temp).lstrip(', ') return result df_black['違反法条'] = df_black['違反法条'].apply(ihan_conv) df_black['その他参考事項'] = df_black['その他参考事項'].apply(sonota_conv) # CSVファイルへ出力 df_black.to_csv('black.csv') # TSVファイルへ出力 df_black.to_csv('black.tsv', sep='\t' ) # EXCELファイルへ出力 with pd.ExcelWriter('black.xlsx') as writer: df_black.to_excel(writer, sheet_name='sheet1')
camelotは線できちんと囲まれているものは大丈夫そう。 2行で1つのセルのようなexcelで1つは線ありもう一つは文字オーバーして線が消えていると隣や上にくっついてしまうので難しい。
colspanがめんどくさいので直取り
import requests from bs4 import BeautifulSoup headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko' } def get_table(url): r = requests.get(url, headers=headers) if r.status_code == requests.codes.ok: soup = BeautifulSoup(r.content, 'html5lib') tables = soup.find_all('table', class_='datatable') return tables def scraping(tables, num, area): # 今週 this_week = float(tables[4].select_one( 'tr:nth-of-type(3) > td:nth-of-type({})'.format(num + 1)).get_text( strip=True)) # 前週 last_week = float(tables[4].select_one( 'tr:nth-of-type(5) > td:nth-of-type({})'.format(num)).get_text( strip=True)) # 警報・注意報 alarm = tables[4].select_one( 'tr:nth-of-type(4) > td:nth-of-type({})'.format(num - 1)).get_text( strip=True) # 前週差 comp_week = this_week - last_week if comp_week > 0: sign = '↑' elif comp_week < 0: sign = '↓' else: sign = '' # インフルエンザ患者報告数 this_count = tables[0].select_one( 'tr:nth-of-type(2) > td:nth-of-type({})'.format(num)).get_text( strip=True) # 迅速検査結果 temp = [] inful_a = tables[0].select_one( 'tr:nth-of-type(4) > td:nth-of-type({})'.format(num + 1)).get_text( strip=True) inful_b = tables[0].select_one( 'tr:nth-of-type(5) > td:nth-of-type({})'.format(num)).get_text( strip=True) inful_n = tables[0].select_one( 'tr:nth-of-type(6) > td:nth-of-type({})'.format(num)).get_text( strip=True) if inful_a: temp.append('A型:{}人'.format(inful_a)) if inful_b: temp.append('B型:{}人'.format(inful_b)) if inful_n: temp.append('不明:{}人'.format(inful_n)) inful_kata = '、'.join(temp) result = '({0}){1}\n定点当たり:{2:.1f}人{3}(前週比:{4:+.1f}人)\n患者報告数:{5}人({6})'.format( area, alarm, this_week, sign, comp_week, this_count, inful_kata) return result # 02:愛媛県 # 03:四国中央 # 04:西条 # 05:今治 # 06:松山市 # 07:中予 # 08:八幡浜 # 09:宇和島 if __name__ == '__main__': tables = get_table( 'https://www.pref.ehime.jp/h25115/kanjyo/topics/influ1819/tb_flu1819.html' ) tables.extend( get_table( 'https://www.pref.ehime.jp/h25115/kanjyo/topics/influ1819/index1819.html' )) # print(len(tables)) if len(tables) == 5: temp = [] temp.append('インフルエンザ患者報告数') temp.append(scraping(tables, 2, '愛媛県')) temp.append(scraping(tables, 5, '今治')) temp.append('https://www.pref.ehime.jp/h25115/kanjyo/index.html') result = '\n\n'.join(temp) print(result)続きを読む
import csv import time from urllib.parse import parse_qs, urljoin, urlparse import requests from bs4 import BeautifulSoup headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko' } def scraping(url): r = requests.get(url, headers=headers) if r.status_code == requests.codes.ok: soup = BeautifulSoup(r.content, 'html5lib') result = [ td.get_text(strip=True) for td in soup.select('table#hor-zebra > tbody > tr > td') ] # GooglemapからURL取得 gmap = soup.select_one( 'table#jyouhou-table > tbody > tr > td > div > iframe').get('src') # URLからquery取得 temp = parse_qs(urlparse(gmap).query) # queryから緯度・経度取得 lon, lat = temp['q'][0].replace('loc:', '').split(',') return ([lon, lat] + result) if __name__ == '__main__': # 愛媛県歯科医師会より今治市の歯科医院を探す url = 'https://www.ehimeda.or.jp/doctor/sdental_u/resultlist.php?selADD1=02&SelCount=5' r = requests.get(url, headers=headers) if r.status_code == requests.codes.ok: soup = BeautifulSoup(r.content, 'html5lib') with open('result.csv', 'w') as fw: writer = csv.writer(fw, dialect='excel', lineterminator='\n') # ヘッダーをスキップするため1からスタート for trs in soup.select('table#list-table > tbody > tr')[1:]: result = [td.get_text(strip=True) for td in trs.select('td')] link = urljoin(url, trs.select_one('a').get('href')) temp = scraping(link) writer.writerow(result + temp) time.sleep(1)
[http://kk6.hateblo.jp/entry/2018/12/17/Pipenv%E3%81%8B%E3%82%89_Poetry%E3%81%B8%E3%81%AE%E4%B9%97%E3%82%8A%E6%8F%9B%E3%81%88:embed:cite]