Scrapy之資料解析與資料持久化儲存
JS反混淆:將js混淆的密文以原文的形式展示。推薦的解密網址:http://www.bm8.com.cn/jsConfusion/
需要通過python呼叫js的相關程式碼:
PyExecJS:可以讓python對js程式碼進行模擬執行。
環境的安裝:
pip install PyExecJS -i http://www.bm8.com.cn/jsConfusion/
- 安裝nodeJS的環境,百度下載即可
使用:
#test.js檔案內容
functiontest_function(start,end){
varparam;
param=start-end;
returnparam;
}
importexecjs
node=execjs.get()
#Compilejavascript
ctx=node.compile(open('test.js',encoding='utf-8').read())
#Getparams,注意傳入引數的格式,從0開始
js='test_function("{0}","{1}")'.format(20,4)
param=ctx.eval(js)
param#4
Scrapy框架
除此之外還有pySpider框架
框架:就是一個具有很強通用性且集成了很多功能的專案模板(可以被應用在各種需求中)
scrapy整合好的功能:
- 高效能的資料解析操作(xpath)
- 高效能的資料下載
- 高效能的持久化儲存
- 中介軟體
- 全棧資料爬取操作
- 分散式:只能用redis資料庫
- 請求傳參的機制(深度爬取)
- scrapy中合理的應用selenium
環境的安裝(Windows)
pip install wheel -i https://pypi.tuna.tsinghua.edu.cn/simple
下載twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/ # twisted
進入下載目錄,執行
pip install .\Twisted-20.3.0-cp39-cp39-win_amd64.whl
pip install pywin32 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install scrapy -i https://pypi.tuna.tsinghua.edu.cn/simple
twisted是一個非同步的元件。scrapy引用twisted來實現非同步操作。
建立工程
scrapy startproject ProName
cd ProName
scrapy genspider spiderName www.xxx.com
,建立爬蟲檔案,網址之後還能改- 執行工程:
scrapy crawl spiderName
第三步執行後會在專案下spiders資料夾建立一個spiderName.py檔案。
spiderName.py檔案初始內容:
importscrapy
classspiderNameSpider(scrapy.Spider):
#爬蟲檔名稱,爬蟲檔案的唯一標識
name='spiderName'
#允許的域名,只有在此域名之下的url才能請求成功,一般將其註釋掉
#allowed_domains=['www.xxx.com']
#起始的url列表,通常方網站的首頁url;列表中的列表元素會被scrapy自動的進行請求傳送
start_urls=['http://www.xxx.com/']
#解析資料
defparse(self,response):
#呼叫xpath解析
response.xpath('xpath表示式')
#不能使用with開啟文字儲存資料,因為請求是非同步的
scrapy預設遵從robots協議,可在專案目錄下的settings.py中修改配置:
settings.py:
ROBOTSTXT_OBEY = False
不遵從robots協議,預設為True
其它配置:
- UA偽裝:配置
USER_AGENT=
LOG_LEVEL = 'ERROR'
,只輸出ERROR型別的日誌LOG_FILE = 'log.txt'
將日誌輸出到log.txt檔案
scrapy中xpath資料解析,與xpath模組不同之處:
xpath返回的列表中的列表元素是Selector物件,要獲取的字串的資料在該物件中。如
response.xpath('.//text()')[0]
會返回一個物件,不會返回字串,取出text文字內容:response.xpath('.//text()')[0].extract()
或response.xpath('.//text()').extract_first()
。extract():取列表中的每一個Selector列表元素物件的文字內容,返回列表
extract_first():列表元素只有單個,返回字串。
scrapy的持久化儲存
基於終端指令:
- 只可以將parse方法的返回值儲存到磁碟檔案中
- 指令
scrapy crawl spiderName -o file_name.csv
file_name檔案字尾不能是.txt,可以是'json', 'jsonlines', '
jl', 'csv', 'xml', 'marshal', 'pickle'等。
示例:
importscrapy
classspiderNameSpider(scrapy.Spider):
name='spiderName'
start_urls=['http://www.xxx.com/']
defparse(self,response):
data=response.xpath('xpath表示式').extract_first()
returndata
#終端中執行:
scrapycrawlspiderName-ofile_name.csv
基於管道:專案中的pipelines.py檔案,編碼流程:
- 資料解析
- 在item.py檔案中item的類中定義相關的屬性
- 將解析的資料儲存封裝到item型別的物件中。
- 將item物件提交給管道
- 在管道類中的process_item方法負責接收item物件,然後對item進行任意形式的持久化儲存
- 在配置檔案中開啟管道,開啟
ITEM_PIPELINES
,
細節補充:
- 管道檔案中的一個管道類表示將資料儲存到某一種形式的平臺中。
- ITEM_PIPELINES字典中鍵對應的數字是優先順序,值越小優先順序越高,如果管道檔案中定義了多個管道類,爬蟲類提交的item會給到優先順序最高的管道類。
- process_item方法的實現中的return item的操作表示將item傳遞給下一個即將被執行的管道類。
簡單使用示例,爬取虎牙直播:
#配置:
scrapystartprojecthuyaPro
cdhuyaPro
scrapygenspiderhuyawww.xxx.com
#settings.py
BOT_NAME='huyaPro'
SPIDER_MODULES=['huyaPro.spiders']
NEWSPIDER_MODULE='huyaPro.spiders'
#Crawlresponsiblybyidentifyingyourself(andyourwebsite)ontheuser-agent
USER_AGENT='Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/84.0.4147.105Safari/537.36'
#Obeyrobots.txtrules
ROBOTSTXT_OBEY=False
LOG_LEVEL='ERROR'
#Configureitempipelines
#Seehttps://docs.scrapy.org/en/latest/topics/item-pipeline.html
#6.在配置檔案中開啟管道
ITEM_PIPELINES={
'huyaPro.pipelines.HuyaproPipeline':300,
'huyaPro.pipelines.MysqlPipeLine':301,
'huyaPro.pipelines.RedisPipeLine':302,
}
#items.py
importscrapy
classHuyaproItem(scrapy.Item):
#definethefieldsforyouritemherelike:
#Field是一個萬能的資料型別,可以儲存任何資料型別
#name=scrapy.Field()
#2.在item類中定義相關屬性
title=scrapy.Field()
author=scrapy.Field()
hot=scrapy.Field()
#spiders/huya.py
importscrapy
#基於管道儲存,匯入類
fromhuyaPro.itemsimportHuyaproItem
classHuyaSpider(scrapy.Spider):
name='huya'
#allowed_domains=['www.xxx.com']
start_urls=['https://www.huya.com/g/4079']
defparse(self,response):
#基於終端儲存
#all_data_list=[]
#1.資料解析
li_list=response.xpath('//*[@id="js-live-list"]/li')
forliinli_list:
#title=li.xpath('./a[2]/text()')[0]<Selectorxpath='./a[2]/text()'data='餘生...'>
title=li.xpath('./a[2]/text()').extract_first()
author=li.xpath('./span/span[1]/i/text()').extract_first()
hot=li.xpath('././span/span[2]/i[2]/text()').extract_first()
'''基於終端儲存
dic={
'title':title,
'author':author,
'hot':hot,
}
all_data_list.append(dic)
returnall_data_list
#終端輸入scrapycrawlhuya-ohuya.csv
'''
#管道儲存。
#例項化item型別的物件
item=HuyaproItem()
#3.將解析的資料封裝到item型別的物件中,注意需要通過[]調物件的屬性。
item['title']=title
item['author']=author
item['hot']=hot
#print(item)item相當於一個字典
#將item物件提交給管道
yielditem
#pipelines.py
#將資料寫入磁碟檔案,一個管道類表示將資料儲存到某一種形式的平臺中
classHuyaproPipeline:
fp=None
#重寫父類方法,該方法只會在爬蟲開始的時候執行一次
defopen_spider(self,spider):
self.fp=open('./huya.txt','w',encoding='utf-8')
#5.process_item負責接收item物件,在爬蟲期間,該方法可能會執行多次,因此不能在此方法開啟檔案
defprocess_item(self,item,spider):
self.fp.write(item['author']+':'+item['title']+item['hot'])
#將item傳遞給下一個即將被執行的管道類
returnitem
#重寫父類方法,該方法只會在爬蟲結束的時候執行一次
defclose_spider(self,spider):
self.fp.close()
#將資料寫入mysql資料庫中
importpymysql
classMysqlPipeLine(object):
conn=None
defopen_spider(self,spider):
self.conn=pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='1',db='Spider',charset='utf8')
defprocess_item(self,item,spider):
sql='insertintohuyavalues("%s","%s","%s")'%(item['author'],item['title'],item['hot'])
self.cursor=self.conn.cursor()
try:
self.cursor.execute(sql)
self.conn.commit()
exceptExceptionase:
print(e)
self.conn.rollback()
#一定要寫return,不然下一個管道類無法獲取item
returnitem
defclose_spider(self,spider):
self.cursor.close()
self.conn.close()
#寫入redis資料庫
fromredisimportRedis
classRedisPipeLine(object):
conn=None
defopen_spider(self,spider):
self.conn=Redis(host='127.0.0.1',port=6379)
defprocess_item(self,item,spider):
#item本身就是一個字典,因此可以使用佇列資料結構
self.conn.lpush('huyaList',item)
#returnitem#可以不寫,沒有下個管道類
defclose_spider(self,spider):
self.conn.close()