最近學(xué)習(xí)了scrapy爬蟲(chóng)框架,想要找個(gè)目標(biāo)練練手。由于現(xiàn)在很多網(wǎng)頁(yè)都是動(dòng)態(tài)的,因此還需要配合selenium爬取。本文旨在記錄這次學(xué)習(xí)經(jīng)歷,如有疑問(wèn)或不當(dāng)之處,可以在評(píng)論區(qū)指出,一起學(xué)習(xí)。
scrapy與selenium
對(duì)scrapy不了解的同學(xué)可以閱讀這篇文章 爬蟲(chóng)框架 Scrapy 詳解,對(duì)scrapy框架介紹的非常詳盡。
Selenium簡(jiǎn)單來(lái)說(shuō)就是一種用于測(cè)試Web應(yīng)用程序的自動(dòng)化工具。它可以模擬用戶在瀏覽器中的各種操作,如點(diǎn)擊、輸入、選擇、拖放等,以及對(duì)頁(yè)面進(jìn)行斷言驗(yàn)證。在這里可以幫助我們獲取到動(dòng)態(tài)網(wǎng)頁(yè)的數(shù)據(jù)。
準(zhǔn)備工作
相關(guān)庫(kù)以及chromedriver的安裝
我們需要安裝兩個(gè)庫(kù),一個(gè)是selenium庫(kù),還有一個(gè)是scrapy庫(kù)。
pip install selenium // 安裝selenium庫(kù)
pip install scrapy // 安裝scrapy庫(kù)
除此之外,還需要安裝chromedriver.exe,如果電腦上沒(méi)有谷歌瀏覽器就還需要安裝谷歌瀏覽器。chromedriver.exe的安裝可以看我的這篇文章python爬蟲(chóng)學(xué)習(xí)日志 使用selenium爬取動(dòng)態(tài)網(wǎng)頁(yè)數(shù)據(jù)
目標(biāo)內(nèi)容
獲取某站目標(biāo)視頻的標(biāo)題、播放量、發(fā)布日期、時(shí)長(zhǎng)、點(diǎn)贊量、投幣量、收藏量。
由于版權(quán)問(wèn)題這里不能放出相應(yīng)視頻的圖片,各位如有需要可以自行了解。
具體實(shí)現(xiàn)
準(zhǔn)備工作完成之后就可以開(kāi)始編寫(xiě)我們的代碼啦~
創(chuàng)建項(xiàng)目
打開(kāi)pycharm的終端或者cmd窗口,進(jìn)入想要放置爬蟲(chóng)文件的目錄,我這里是直接在pycharm的項(xiàng)目目錄里創(chuàng)建的,然后輸入以下命令
scrapy startproject bili //bili是自定義的爬蟲(chóng)項(xiàng)目名稱
如果返回了以下信息,說(shuō)明項(xiàng)目創(chuàng)建成功了。
然后我們就可以在pycharm左側(cè)的文件欄看到我們創(chuàng)建的爬蟲(chóng)項(xiàng)目里的文件了。
創(chuàng)建之后,我們需要把下載的chromedriver.exe文件移至和scrapy.cfg同目錄下,如圖所示。
編寫(xiě)items.py文件
items.py文件是用來(lái)定義我們需要爬取的數(shù)據(jù)的,首先編輯它可以幫我們完成數(shù)據(jù)建模,之后按照items.py中的變量來(lái)匹配我們的數(shù)據(jù)就行了。
import scrapy
class BiliItem(scrapy.Item):
// define the fields for your item here like:
// name = scrapy.Field()
// 這是scrapy提供給我們建模的格式,按照這個(gè)來(lái)就行
title = scrapy.Field() //視頻標(biāo)題
play = scrapy.Field() // 播放量
dianzan = scrapy.Field() //點(diǎn)贊量
toubi = scrapy.Field() //投幣量
shoucang = scrapy.Field() //收藏量
date = scrapy.Field() //發(fā)布日期
time = scrapy.Field() //視頻時(shí)長(zhǎng)
這樣一來(lái),我們的items.py就文件就算編寫(xiě)完成了。
編寫(xiě)middlewares.py文件
接下來(lái)編寫(xiě)middlewares.py文件,也就是中間件。
中間件包括兩種中間件,一種是爬蟲(chóng)中間件,還有一種是下載器中間件,每種中間件都有自己對(duì)應(yīng)的功能,這里不再展開(kāi)講,想要了解的同學(xué)可以自己去查找相關(guān)信息。在這次實(shí)戰(zhàn)中我們只需要通過(guò)編寫(xiě)下載器中間件對(duì)接selenium實(shí)現(xiàn)獲取動(dòng)態(tài)網(wǎng)頁(yè)的源碼這一功能。
代碼如下:
from scrapy import signals
from selenium import webdriver
from scrapy.http import HtmlResponse
// 只需要修改下載器中間件,爬蟲(chóng)中間件不用管
class BiliDownloaderMiddleware:
// 當(dāng)下載器中間件開(kāi)始工作時(shí),自動(dòng)打開(kāi)一個(gè)瀏覽器
def __init__(self):
self.driver = webdriver.Chrome()
@classmethod
def from_crawler(cls, crawler):
# This method is used by Scrapy to create your spiders.
s = cls()
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
// 下面這一行需要手動(dòng)添加,作用是調(diào)用關(guān)閉瀏覽器的函數(shù)
crawler.signals.connect(s.spider_closed, signal=signals.spider_closed)
return s
// 每當(dāng)爬蟲(chóng)文件向目標(biāo)網(wǎng)址發(fā)送一次請(qǐng)求都會(huì)調(diào)用這個(gè)函數(shù),用處就是返回該網(wǎng)址的源碼
def process_request(self, request, spider):
self.driver.get(request.url) // 使用瀏覽器打開(kāi)請(qǐng)求的URL
body = self.driver.page_source // 獲取網(wǎng)頁(yè)HTML源碼
return HtmlResponse(url=self.driver.current_url, body=body, encoding='utf-8', request=request)
def process_response(self, request, response, spider):
return response
def process_exception(self, request, exception, spider):
pass
def spider_opened(self, spider):
spider.logger.info("Spider opened: %s" % spider.name)
// 該函數(shù)需要手動(dòng)添加,作用是關(guān)閉瀏覽器
def spider_closed(self, spider):
self.driver.close()
spider.logger.info("Spider closed: %s" % spider.name)
編寫(xiě)爬蟲(chóng)文件
完成了中間件的編寫(xiě)之后就可以開(kāi)始編寫(xiě)我們的爬蟲(chóng)文件了。爬蟲(chóng)文件需要我們手動(dòng)創(chuàng)建。具體流程是在spiders目錄下新建一個(gè).py文件,文件名可以自擬。
創(chuàng)建之后,就可以編寫(xiě)爬蟲(chóng)文件了。代碼如下
// 使用哪種解析庫(kù)可以根據(jù)自己的習(xí)慣選擇,只要能獲得目標(biāo)數(shù)據(jù)就行
import scrapy
from bs4 import BeautifulSoup
// 這里需要導(dǎo)入之前編寫(xiě)的items.py文件中的BiliItem類,[..]表示上一目錄
from ..items import BiliItem
import re
from lxml import etree
class bilibili(scrapy.Spider): // 類名自擬,但是一定要在括號(hào)里寫(xiě)scrapy.Spider表示繼承父類
name = 'bilibili' // 爬蟲(chóng)名,自擬
allowed_domains = ['space.bilibili.com'] // 定義域名,相當(dāng)于是給爬蟲(chóng)規(guī)定了爬取的范圍
start_urls = ['https://space.bilibili.com/1629347259/video'] // 定義開(kāi)始爬取的網(wǎng)頁(yè)
page = 1 // 如果想要爬取多頁(yè)數(shù)據(jù),需要定義爬取初始的頁(yè)數(shù),這里是1
// 后續(xù)頁(yè)數(shù)的網(wǎng)址,需要自己觀察翻頁(yè)后網(wǎng)址的變化得出規(guī)律
base_url = 'https://space.bilibili.com/1629347259/video?tid=0&page={}'
// 重寫(xiě)父類方法,解析相應(yīng)網(wǎng)頁(yè)
def parse(self, response, **kwargs):
// 這里的response是下載器中間件返回給爬蟲(chóng)的網(wǎng)頁(yè)源碼,對(duì)此進(jìn)行解析即可獲得想要的數(shù)據(jù)
// 以下內(nèi)容都是根據(jù)相應(yīng)的網(wǎng)頁(yè)源碼選擇合適的方法進(jìn)行數(shù)據(jù)的提取,可以根據(jù)自己的需求編寫(xiě)。
bs = BeautifulSoup(response.text, 'lxml')
// tag_list是一個(gè)包括了很多個(gè)tag標(biāo)簽的列表,每個(gè)tag標(biāo)簽中都有視頻的網(wǎng)址、標(biāo)題、時(shí)長(zhǎng)等數(shù)據(jù)
tag_list = bs.select('#submit-video-list > ul.clearfix.cube-list > li')
// 遍歷取出每個(gè)tag標(biāo)簽
for index, j in enumerate(tag_list):
// 創(chuàng)建一個(gè)item實(shí)例,用于存儲(chǔ)相應(yīng)數(shù)據(jù),它類似于字典
item = BilibiliItem()
// 獲得網(wǎng)址,但這個(gè)網(wǎng)址不完整
video_url = j.a['href']
// 獲得視頻標(biāo)題文本
video_title = j.find('a', class_='title').text
// 獲得視頻時(shí)長(zhǎng)文本
video_time = j.find('span', class_="length").text
// 使用正則表達(dá)式把獲得到的不完整的網(wǎng)址修改為正確的網(wǎng)址,之后可以進(jìn)入這些網(wǎng)址再獲取其他數(shù)據(jù)
pattern = r'//'
video_url = re.sub(pattern, 'https://', video_url)
// 將標(biāo)題和時(shí)長(zhǎng)以鍵值對(duì)的形式寫(xiě)進(jìn)item實(shí)例中。
item['title'] = video_title
item['time'] = video_time
// 這里需要用yield將相應(yīng)數(shù)據(jù)提交給引擎,由引擎分配后續(xù)工作
// url=video_url表示會(huì)將視頻的網(wǎng)址提交給引擎,引擎會(huì)把這個(gè)網(wǎng)址轉(zhuǎn)交給中間件,中間件又會(huì)將相應(yīng)源碼提供給爬蟲(chóng)文件
// callback表示獲取到相應(yīng)源碼后會(huì)將它交給爬蟲(chóng)文件中哪個(gè)函數(shù)進(jìn)行處理
// meta={'item': item}的作用是把目前的item實(shí)例轉(zhuǎn)移給下一個(gè)函數(shù)使用或編輯。
// dont_fillter=True表示不過(guò)濾重復(fù)的請(qǐng)求。
yield scrapy.Request(url=video_url, callback=self.parse_detail, meta={'item': item}, dont_filter=True)
// 如果需要爬多頁(yè)數(shù)據(jù)可以編寫(xiě)這一串代碼,具體多少頁(yè)可以根據(jù)自己的需求來(lái)
if self.page <= 3:
self.page += 1
new_url = self.base_url.format(self.page)
yield scrapy.Request(url=new_url, callback=self.parse)
// 這里是定義對(duì)視頻網(wǎng)址信息的獲取的函數(shù),思路與parse()函數(shù)類似
def parse_detail(self, response):
html = etree.HTML(response.text)
play = html.xpath('//*[@id="viewbox_report"]/div/div/span[1]/text()')
date = html.xpath('//*[@id="viewbox_report"]/div/div/span[3]/span/span/text()')
dianzan = html.xpath('//*[@id="arc_toolbar_report"]/div[1]/span[1]/span/text()')
toubi = html.xpath('//*[@id="arc_toolbar_report"]/div[1]/span[2]/span/text()')
shoucang = html.xpath('//*[@id="arc_toolbar_report"]/div[1]/span[3]/span/text()')
item = response.meta['item']
item['play'] = play[0].strip()
item['date'] = date[0].strip()
item['dianzan'] = dianzan[0].strip()
item['toubi'] = toubi[0].strip()
item['shoucang'] = shoucang[0].strip()
// 所有數(shù)據(jù)都寫(xiě)入item實(shí)例后就可以向引擎提交了,每個(gè)item包括了一個(gè)視頻的相關(guān)數(shù)據(jù),之后引擎會(huì)把item交給pipeline處理。
yield item
編寫(xiě)pipelines.py文件
爬蟲(chóng)文件的作用是將爬取到的數(shù)據(jù)暫時(shí)保存在內(nèi)存中,如果想要將數(shù)據(jù)保存至本地或者數(shù)據(jù)庫(kù)中就需要通過(guò)編寫(xiě)pipelines.py文件來(lái)實(shí)現(xiàn)了。
這里我選擇的是保存為excel文件,需要用到openyxl庫(kù),代碼如下:
import openpyxl
class BiliPipeline:
def __init__(self):
print('開(kāi)始寫(xiě)入')
self.wb = openpyxl.Workbook()
self.ws = self.wb.active # 獲取活動(dòng)表
self.ws.append(['視頻標(biāo)題', '視頻播放量', '視頻點(diǎn)贊量', '視頻投幣量', '視頻收藏量', '視頻發(fā)布日期', '視頻時(shí)長(zhǎng)']) # 添加表頭
def process_item(self, item, spider):
print(f'正在保存:{item["title"]}')
line = [item['title'], item['play'], item['dianzan'], item['toubi'], item['shoucang'], item['date'], item['time']]
self.ws.append(line)
return item
def close_spider(self, spider):
self.wb.save('video.xlsx')
self.wb.close()
print('保存完畢')
編寫(xiě)setting.py文件
所有文件編寫(xiě)完成之后,我們還需要打開(kāi)setting.py文件進(jìn)行設(shè)置,確保所有功能能夠正常進(jìn)行。
以下是需要修改或取消注釋的內(nèi)容,沒(méi)有寫(xiě)的默認(rèn)即可。
// 不遵守robottxt協(xié)議,將True改為False
ROBOTSTXT_OBEY = False
// 在請(qǐng)求頭中添加自己瀏覽器的UA信息
DEFAULT_REQUEST_HEADERS = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en",
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36 QIHU 360SE'
}
// 取消下載器中間件的注釋
DOWNLOADER_MIDDLEWARES = {
"bili.middlewares.BiliDownloaderMiddleware": 543,
}
// 取消item_pipelines的注釋
ITEM_PIPELINES = {
"bili.pipelines.BiliPipeline": 300,
}
// 設(shè)置一般日志不顯示,只顯示等級(jí)為警告以上的日志
LOG_LEVEL = "WARNING"
啟動(dòng)爬蟲(chóng)和查看數(shù)據(jù)
這樣一來(lái)所有的代碼都編寫(xiě)完成了,之后我們可以在爬蟲(chóng)項(xiàng)目的根目錄下,通過(guò)pycharm新建一個(gè)start.py文件。
在該文件中,輸入以下代碼并執(zhí)行:
from scrapy import cmdline
cmdline.execute('scrapy crawl bili'.split(' '))
也可以通過(guò)cmd窗口進(jìn)入爬蟲(chóng)項(xiàng)目根目錄下輸入以下指令:
scrapy crawl bili
都可以啟動(dòng)我們的爬蟲(chóng),啟動(dòng)完成之后等待爬蟲(chóng)程序自然關(guān)閉,就可以在根目錄下看到我們爬取到的video.xlsx文件了。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-469414.html
這樣一來(lái),本次的爬蟲(chóng)實(shí)戰(zhàn)就圓滿完成了。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-469414.html
到了這里,關(guān)于python爬蟲(chóng)實(shí)戰(zhàn) scrapy+selenium爬取動(dòng)態(tài)網(wǎng)頁(yè)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!