1. 程式人生 > 實用技巧 >Scrapy之資料解析與資料持久化儲存

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)

  1. pip install wheel -i https://pypi.tuna.tsinghua.edu.cn/simple

  2. 下載twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/ # twisted

  3. 進入下載目錄,執行 pip install .\Twisted-20.3.0-cp39-cp39-win_amd64.whl

  4. pip install pywin32 -i https://pypi.tuna.tsinghua.edu.cn/simple

  5. pip install scrapy -i https://pypi.tuna.tsinghua.edu.cn/simple

twisted是一個非同步的元件。scrapy引用twisted來實現非同步操作。

建立工程

  1. scrapy startproject ProName
  2. cd ProName
  3. scrapy genspider spiderName www.xxx.com ,建立爬蟲檔案,網址之後還能改
  4. 執行工程: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檔案,編碼流程:

  1. 資料解析
  2. 在item.py檔案中item的類中定義相關的屬性
  3. 將解析的資料儲存封裝到item型別的物件中。
  4. 將item物件提交給管道
  5. 在管道類中的process_item方法負責接收item物件,然後對item進行任意形式的持久化儲存
  6. 在配置檔案中開啟管道,開啟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()