使用Selenium+PhantomJS进行对生成内容的JavaScript网站进行爬取
首先
通过JavaScript生成内容的网站,仅使用BeautifulSoup4通常无法进行网页爬取。
例如,像“当滚动到底部时,下一段内容才会显示”的网站。
由于URL不会发生变化,我们该如何处理呢……。
这时就出现了Selenium+PhantomJS的用法。
Background
出于想要在各种不同情况下都能进行网络爬虫的愿望,本次我们将再次参考《Python网络爬虫与数据采集》这本书进行实践。
简单地说,网络爬虫是一件乐趣无穷的事情。
要做的事情
个别重要信息、比如标题、作者和发布日期。
-
- タイトル
-
- URL
- 概要
提取,并将其保存在MongoDB、csv和RSS中。
你能做什么呢?
流动
-
- 使用Selenium和PhantomJS从一个使用JavaScript的网站(本次为“note”)中提取HTML
-
- 使用BeautifulSoup4解析提取的HTML,并提取所需信息
将数据保存到MongoDB
将数据保存为csv格式
将数据保存为RSS格式
保護是我們的責任
-
- Windows10 64bit
-
- Python3.7
-
- MongoDB 4.0.2
-
- Selenium 3.14.0
-
- PhantomJS 2.1.1
- beautifulsoup4 4.6.3
准备工作
-
- PhantomJSをダウンロードし、解凍し、PATHを通しておく必要があります。
参考:「Windowsでphantomjsをインストールしてスクリーンキャプチャ(cygwin実行)」
コードを実行する前にMongoDBをインストールし、起動させておく必要があります。
参考:「Windows版MongoDBのインストール・MongoShellを通してCRUDコマンドを打ってみる」
程式碼 mǎ)
0. 用于日志的咒语
请参考:请停止使用print和import logging来输出日志 – Qiita
from logging import getLogger, StreamHandler, DEBUG
logger = getLogger(__name__)
handler = StreamHandler()
handler.setLevel(DEBUG)
logger.setLevel(DEBUG)
logger.addHandler(handler)
logger.propagate = False
使用Selenium和PhantomJS从JavaScript网站中进行HTML数据抓取。
如果出现 AttributeError: ‘NoneType’对象没有属性 ‘attrs’ 的情况,请将 sleep_time 的数量增加并重新运行。
import sys
import time
from selenium import webdriver # pip install selenium
from selenium.webdriver.support.ui import WebDriverWait
from bs4 import BeautifulSoup
# スクレイピングするサイトのurlを指定
url = 'https://note.mu/'
# 読み込む投稿の多さを指定(amount * 10 投稿程度)
amount = 2
# 読み込み時に待機する時間の指定
sleep_time = 5
def main():
"""
メイン処理
"""
# PhantomJS本体のパスを指定
pjs_path = r"C:\phantomjs-2.1.1\bin\phantomjs.exe"
driver = webdriver.PhantomJS(executable_path=pjs_path)
# ページの読み込み
navigate(driver, url, amount=amount, sleep_time=sleep_time)
# データの抽出
posts = scrape_posts(driver, url)
return posts
def navigate(driver, url, amount=1, sleep_time = 5):
"""
目的のページに遷移する
amount >= 1
"""
logger.debug('Navigating...')
driver.get(url)
assert 'note' in driver.title
# 指定した回数分、ページ下部までスクロールしてコンテンツの生成を待つ
for i in range(1, amount+1):
driver.execute_script('scroll(0, document.body.scrollHeight)')
logger.debug('Waiting for contents to be loaded...({0} times)'.format(i))
time.sleep(sleep_time)
def scrape_posts(driver, url):
"""
投稿のURL、タイトル、概要のdictをリスト形式で取得
"""
posts = []
# Seleniumで取得したHTMLをBeautifulSoup4に読み込む
html = driver.page_source
bsObj = BeautifulSoup(html,"html.parser")
for post_html in bsObj.findAll("div",{"class":"c-card__body"}):
# 記事のURLを取得
content_url = post_html.find("h3").find('a').attrs['href']
content_full_url = url + content_url[1:]
# 記事タイトルを取得
title = post_html.find("h3").find('a').find('span').get_text()
title = title.replace('\n', '') # 改行を削除
# 記事の概要を取得
try:
description = post_html.find("p", {'class':'p-cardItem__description'}).get_text()
description = description.replace('\n', '') # 改行を削除
except AttributeError as e:
description = '-no description-'
logger.debug("「{0}」 has no description: {1}".format(title, e))
posts.append({
'url': content_full_url,
'title': title,
'description': description,
})
return posts
执行
posts = main()
将数据保存到MongoDB中。
在命令提示符上创建数据库目录。
mongod --dbpath "${データベース用のディレクトリへのパス}"
执行。先启动MongoDB。
from pymongo import MongoClient, DESCENDING # pip install pymongo
# MongoDBとの接続
mongo_client = MongoClient('localhost', 27017) # MongoDBと接続
db = mongo_client.note
collection = db.recomend # noteデータベース -> recomendコレクション
collection.delete_many({}) # 既存の全てのドキュメントを削除しておく
def save_to_mongodb(collection, items):
"""
MongoDBにアイテムのリストを保存
"""
result = collection.insert_many(items) # コレクションに挿入
logger.debug('Inserted {0} documents'.format(len(result.inserted_ids)))
# 実行
save_to_mongodb(collection, posts)
用csv格式保存数据
可以将数据保存在CSV文件中,这样非工程师的人也可以使用Excel进行排序和分析,非常方便。
还可以省去安装MongoDB的麻烦。
因此,在这里
-
- MongoDBを経由する場合
- MongoDBを使用しない場合
我会提供两种方法。
因为所创建的csv文件的字符编码是utf-8,所以在Excel中普通打开会出现乱码。请按照以下网站上的步骤来打开:
“在Excel中打开utf-8的CSV文件而不改变字符编码的方法”
import csv
def save_as_csv(posts, csv_name):
# 列名(1行目)を作成
## [タイトル、URL、概要]
col_name = ['title', 'url', 'description']
with open(csv_name, 'w', newline='', encoding='utf-8') as output_csv:
csv_writer = csv.writer(output_csv)
csv_writer.writerow(col_name) # 列名を記入
# csvに1行ずつ書き込み
for post in posts:
row_items = [post['title'], post['url'], post['description']]
csv_writer.writerow(row_items)
# =====
# MongoDBを経由する場合
# from pymongo import MongoClient, DESCENDING # pip install pymongo
# mongo_client = MongoClient('localhost', 27017) # MongoDBと接続
# db = mongo_client.note
# collection = db.recomend # noteデータベース -> recomendコレクション
# posts = collection.find()
# MongoDBを使用しない場合
# postsはmain()の返り値
# =====
# ファイル名を指定
csv_name = 'note_list.csv'
save_as_csv(posts, csv_name)
以RSS格式保存数据。
import feedgenerator # pip install feedgenerator
def save_as_feed(f, posts):
"""
コンテンツリストをRSSフィードとして保存
"""
feed = feedgenerator.Rss201rev2Feed(
title='おすすめノート',
link='https://note.mu/',
description='おすすめノート')
for post in posts:
feed.add_item(title=post['title'], link=post['url'],
description=post['description'], unique_id=post['url'])
feed.write(f, 'utf-8')
# postsは「3. csv形式でデータを保存」を参照
with open('note_recommend.rss', 'w', encoding='utf-8') as f:
save_as_feed(f, posts)
总结
在一些看似无法确定如何进行网页爬取的站点上,当我们滚动到最底部时,下一个内容就会显示出来。但是通过使用Selenium和PhantomJS,我们发现可以进行网页爬取。
请参照以下内容。
代码主要参考了以下内容:2 3。
- 『Pythonクローリング&スクレイピング―データ収集・解析のための実践開発ガイド―』技術評論社
我参考了自己以前的文章。
-
- 「小説家になろう」をPythonでスクレイピングして本文を保存する(自然言語処理用コーパス作成) – Qiita
- YouTubeのAPIで取得した輝夜月さんの動画情報をMongoDBやpandasで触ってみた – Qiita
GitHub: 代码托管平台
我把 Jupyter Notebook 公开在 GitHub 上。
https://github.com/kokokocococo555/JavaScriptScraping-demo
课题
-
- 「1. SeleniumとPhantomJSでJavaScriptサイトからHTMLをスクレイピング」実行時にAttributeError: ‘NoneType’ object has no attribute ‘attrs’が出ることがあるが、原因は未解明。
一応の対処法も記載しているが、どこまで効果があるのやら…。
(2018-09-18追記)エラーが出る理由が書籍のサポートページに載っていた(「P.198, 5.6.2 noteのおすすめコンテンツを取得する」)。対応策も本記事と同じく、time.sleep(2)を入れるという方法。これ以上は放置、という方向でしょうか。
请注意
在进行网页爬虫时,需要注意版权等问题。
请参考以下文章,意识到规则和礼仪。
-
- Webスクレイピングの注意事項一覧 – Qiita
- Webスクレイピングの法律周りの話をしよう! – Qiita
相关文章【网络爬虫和自动化】
基本的なスクレイピング(BeautifulSoup4)
「小説家になろう」をPythonでスクレイピングして本文を保存する(自然言語処理用コーパス作成) – Qiita
APIを利用したスクレイピング・データベースへの保存(MongoDB)・データ分析の一歩(pandas)
YouTubeのAPIで取得した輝夜月さんの動画情報をMongoDBやpandasで触ってみた – Qiita
JavaScriptを用いたサイトのスクレイピング(Selenium, PhantomJS)
JavaScriptでコンテンツが生成されるサイトのスクレイピング【Selenium+PhantomJS】 – Qiita
メール通知(smtplib)・定期的なプログラムの自動実行(タスクスケジューラ)
「小説家になろう」で新しく公開された記事のメール通知を自動化【Python】 – Qiita
自動ログイン(Selenium, ChromeDriver)
QiitaにSeleniumで自動ログインして全投稿を定期的にバックアップ【Python】 – Qiita
在我参考的书籍中,使用Selenium进行解析和信息提取,但是在我的环境中无法成功,所以我使用熟悉的BeautifulSoup4进行处理。↩
由于note的HTML结构与书籍出版时不同,我自己编写了网页抓取的代码。↩
在本文中,我加入了一些改进措施,例如”可以指定要抓取的帖子数量”。↩