■本記事はスクレイピングに関して、3つのことをします。
①google NEWSトップページにあるリンクをスクレイピングする
②googleニュース検索エンジンにキーワード検索をした結果をスクレイピングする
下図のように、タイトルとURLを抽出する。実行する度に、実行した時間をファイル名に記載する仕様であるため、実行の度にファイルが蓄積されてゆくことになる。
③キーワード検索で画像を抽出する(下図)。実行時の抽出するファイル数は指定できる。また、フォルダ名は実行した時間になるため、こちらも実行の度に上書きされることはない。
■インストールする必要があるPythonライブラリ4つ。condaもしくはpipでインストールする。
pip install requests
pip install beautifulsoup4
conda install feedparser
pip install google_images_download
ここで、次の1~4に注意する。画像をスクレイピングするために、google_images_downloadを使用しますが、通常では1回100抽出までの制約条件がある。この制限を回避するために、Chromeブラウザの機能を使用するため、ChromeとChromeDriverをインストールする必要があるが、ChromeとChromeDriverのverが合致しておく必要がある。
▼1. Chromeのバージョンをブラウザのヘルプで確認。この場合、77
▼2. ChromeDriverのverを77を落とす
https://chromedriver.chromium.org/downloads
▼3. zipファイルなので解凍するとexeファイルがあるので、適当な場所に置く(下図)。
▼4. 本プログラム中でパスを通す
"chromedriver": "C:\Program Files (x86)\chromedriver_win32\chromedriver.exe",
■本プログラム
上記の準備をしておけば、コピペで実行可能です。
特記事項は下記2点です。
1. google ニュースのトップページのスクレイピングに関しては、アルゴリズムの関係上、time.sleep(1)を設定して相手側のサーバーに負荷を掛けないようにしています
2. UnicodeEncodeError: 'cp932' codec can't encode character '\u2661' in position 84: illegal multibyte sequence 等の文字コードエラーの対策として、encoding="utf-8_sig" もしくは encoding='utf-16' をデータの読み書きする際に使用しています
import os, glob
import time, datetime
import pprint, csv
import pandas as pd
import requests
from bs4 import BeautifulSoup
import feedparser
from google_images_download import google_images_download
now = datetime.datetime.now()
now = now.strftime("%y%m%d_%H%M%S")
class Scraper:
def __init__(self, site):
self.site = site
def google_news(self, max_num):
r = requests.get(self.site)
sp = BeautifulSoup(r.content, "html.parser")
news = []
buf = ""
n = 1
for tag in sp.find_all("a"):
url = tag.get("href")
if url and "./articles" in url:
if url != buf:
buf = url
url2 = url.replace("./articles", "https://news.google.com/articles")
r2 = requests.get(url2)
sp2 = BeautifulSoup(r2.content, "html.parser")
time.sleep(1)
title2 = sp2.title.string
print(n)
print(title2)
print(url2)
buf2 = [title2, url2]
news.append(buf2)
n += 1
if n==max_num:
break
print("news[]")
print(str(news))
df = pd.DataFrame(news, columns=['title', 'link'])
df = df.replace('\uff0d', 'hoge1').replace('\xa0', 'hoge2')
df2 = df.dropna(subset=['title', 'link'])
df3 = df2.drop_duplicates('link', keep='first')
df3.to_csv(now + "_output_google_news.csv", header=True, index=False, encoding="utf-8_sig")
def google_search(self, keyword):
r = requests.get(self.site)
print(r.url)
d = feedparser.parse(r.url)
news = []
for i, entry in enumerate(d.entries, 1):
p = entry.published_parsed
sortkey = "%04d%02d%02d%02d%02d%02d" % (p.tm_year, p.tm_mon, p.tm_mday, p.tm_hour, p.tm_min, p.tm_sec)
buf = {
"no": i,
"sortkey": sortkey,
"published": entry.published,
"title": entry.title,
"link": entry.link
}
news.append(buf)
news = sorted(news, key=lambda x: x['sortkey'], reverse=True)
pprint.pprint(news)
with open(now + '_output_google_news_search_' + str(keyword.split()) + '.csv', 'w', newline='', encoding='utf-16') as f:
fieldnames = news[0].keys()
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for e in news:
writer.writerow(e)
def scrape_images(keyword, max_num):
dir_name = now + "_" + str(keyword.split())
config = {
"Records":[
{
"keywords": keyword,
"limit": max_num,
"no_numbering": True,
"output_directory": "images",
"image_directory": dir_name,
"chromedriver": "C:\Program Files (x86)\chromedriver_win32\chromedriver.exe",
},
]
}
res = google_images_download.googleimagesdownload()
for rc in config["Records"]:
res.download(rc)
if __name__ == "__main__":
max_num = 20
urlA = "https://news.google.com/?hl=ja&gl=JP&ceid=JP:ja"
scrapeA = Scraper(urlA)
scrapeA.google_news(max_num)
keyword = "株 AI"
urlB = "https://news.google.com/news/rss/search/section/q/" + keyword + "/" + keyword + "?hl=ja&gl=JP&ned=jp"
print(urlB)
scrapeB = Scraper(urlB)
scrapeB.google_search(keyword)
max_num = 20
scrape_images(keyword, max_num)
print("finished")
以上
<広告>
リンク