python爬虫入门 之 移动端数据的爬取
第七章 移動端數(shù)據(jù)的爬取
基于某一款抓包工具 : fiddler ,青花瓷 ,miteproxy
7.1 fiddler 基本配置
7.1.1fiddler簡介和安裝
什么是Fiddler?
Fiddler是位于客戶端和服務(wù)器端的HTTP代理,也是目前最常用的http抓包工具之一 。 它能夠記錄客戶端和服務(wù)器之間的所有 HTTP請求,可以針對特定的HTTP請求,分析請求數(shù)據(jù)、設(shè)置斷點、調(diào)試web應(yīng)用、修改請求的數(shù)據(jù),甚至可以修改服務(wù)器返回的數(shù)據(jù),功能非常強(qiáng)大,是web調(diào)試的利器。
Fiddler安裝
Fiddler下載地址:https://www.telerik.com/fiddler
傻瓜式安裝,一鍵到底。Fiddler軟件界面如圖所示:
7.1.2手機(jī)APP抓包設(shè)置
Fiddler設(shè)置打開Fiddler軟件,打開工具的設(shè)置。(Fiddler軟件菜單欄:Tools->Options)在HTTPS中設(shè)置如下:
在Connections中設(shè)置如下
這里使用默認(rèn)8888端口,當(dāng)然也可以自己更改,但是注意不要與已經(jīng)使用的端口沖突:Allow remote computers to connect:允許別的機(jī)器把請求發(fā)送到fiddler上來
安全證書下載
在電腦瀏覽器中輸入地址:http://localhost:8888/,點擊FiddlerRoot certificate,下載安全證書:
安全證書安裝
證書是需要在手機(jī)上進(jìn)行安裝的,這樣在電腦Fiddler軟件抓包的時候,手機(jī)使用電腦的網(wǎng)卡上網(wǎng)才不會報錯。
Android手機(jī)安裝:
把證書放入手機(jī)的內(nèi)置或外置存儲卡上,然后通過手機(jī)的"系統(tǒng)安全-》從存儲設(shè)備安裝"菜單安裝證書。然后找到拷貝的FiddlerRoot.cer進(jìn)行安裝即可。安裝好之后,可以在信任的憑證中找到我們已經(jīng)安裝好的安全證書。
蘋果手機(jī)安裝:
保證手機(jī)網(wǎng)絡(luò)和fiddler所在機(jī)器網(wǎng)絡(luò)是同一個網(wǎng)段下的在safari中訪問http://fiddle機(jī)器ip:fiddler端口,進(jìn)行證書下載。然后進(jìn)行安裝證書操作。在手機(jī)中的設(shè)置-》通用-》關(guān)于本機(jī)-》證書信任設(shè)置-》開啟fiddler證書信任
局域網(wǎng)設(shè)置 想要使用Fiddler進(jìn)行手機(jī)抓包,首先要確保手機(jī)和電腦的網(wǎng)絡(luò)在一個內(nèi)網(wǎng)中,可以使用讓電腦和手機(jī)都連接同一個路由器。當(dāng)然,也可以讓電腦開放WIFI熱點,手機(jī)連入。這里,我使用的方法是,讓手機(jī)和電腦同時連入一個路由器中。最后,讓手機(jī)使用電腦的代理IP進(jìn)行上網(wǎng)。 在手機(jī)上,點擊連接的WIFI進(jìn)行網(wǎng)絡(luò)修改,添加代理。進(jìn)行手動設(shè)置,ip和端口號都是fiddler機(jī)器的ip和fiddler上設(shè)置的端口號。
Fiddler手機(jī)抓包測試
上述步驟都設(shè)置完成之后,用手機(jī)瀏覽器打開百度首頁,我們就可以順利抓包了
7.1.3移動端數(shù)據(jù)的捕獲流程
tools --> options --> connection -->allow remote
http: fiddler所在pc機(jī)的ip :8888/ 訪問到一張?zhí)峁┝俗C書下載功能的界面
fiddler所在機(jī)器和手機(jī)在同一網(wǎng)段下 :在手機(jī)上瀏覽器中訪問 http: fiddler所在pc機(jī)的ip :8888 獲取子頁面進(jìn)行證書的下載和安裝(證書信任的操作)
配置你手機(jī)的代理 :將手機(jī)的代理配置成 fiddler所對應(yīng)的pc機(jī)的ip和手機(jī)自己的端口
就可以讓fiddler捕獲手機(jī)發(fā)起的http和https的請求
7.2 scrapy ,pyspider
#總結(jié):
?
#爬蟲文件中的屬性和方法
name :爬蟲文件唯一標(biāo)識
start_url:該列表中的url會被自動的進(jìn)行請求發(fā)送
#自動請求發(fā)送的過程:
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(url,callback=self.parse)
?
#數(shù)據(jù)解析:
scrapy中封裝的xpath進(jìn)行數(shù)據(jù)解析
#scrapy中的xpath 和 etree中的xpath的區(qū)別
scrapy的xpath進(jìn)行數(shù)據(jù)解析后返回的列表元素為Selector對象,extract或extract_first這兩個方法將Selector對象中對應(yīng)的數(shù)據(jù)取出
View Code
7.2.1Scrapy簡介
什么是框架?如何學(xué)習(xí)
框架就是一個集成各種功能且具有很強(qiáng)通用性(可以被應(yīng)用在各種不同的需求中)的一個項目模板
我們只需要學(xué)習(xí)框架中封裝好的相關(guān)功能即可
scrapy 集成的功能
高性能的數(shù)據(jù)解析操作 ,持久化存儲,高性能的數(shù)據(jù)下載操作......
環(huán)境的安裝(windows)
pip install wheel
下載twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/
進(jìn)入下載目錄,執(zhí)行 pip3 install Twisted?17.1.0?cp35?cp35m?win_amd64.whl
pip3 install pywin32
pip3 install scrapy
7.2.2 scrapy的基本使用
創(chuàng)建一個工程 :scrapy startproject firstBlood
項目結(jié)構(gòu):
project_name/
scrapy.cfg: #項目的主配置信息。(真正爬蟲相關(guān)的配置信息在settings.py文件中)
project_name/
__init__.py
items.py #設(shè)置數(shù)據(jù)存儲模板,用于結(jié)構(gòu)化數(shù)據(jù),如:Django的Model
pipelines.py #數(shù)據(jù)持久化處理
settings.py #配置文件,如:遞歸的層數(shù)、并發(fā)數(shù),延遲下載等
spiders/ #爬蟲目錄,如:創(chuàng)建文件,編寫爬蟲解析規(guī)則
__init__.py
創(chuàng)建爬蟲應(yīng)用程序:(必須在spider這個目錄下創(chuàng)建一個爬蟲文件)
cd proName
scrapy genspider spiderName http://t.zoukankan.com/www.xx.com
編寫爬蟲文件:在步驟2執(zhí)行完畢后,會在項目的spiders中生成一個應(yīng)用名的py爬蟲文件
import scrapy
class FirstSpider(scrapy.Spider):
#爬蟲文件的名稱:爬蟲文件的唯一標(biāo)識(在spiders子目錄下是可以創(chuàng)建多個爬蟲文件)
name = 'first'
#允許的域名
# allowed_domains = ['www.baidu.com']
#起始的url列表:列表中存放的url會被scrapy自動的進(jìn)行請求發(fā)送
start_urls = ['https://www.baidu.com/','https://www.sogou.com/']
#用作于數(shù)據(jù)解析:將start_urls列表中對應(yīng)的url請求成功后的響應(yīng)數(shù)據(jù)進(jìn)行解析
def parse(self, response):
print(response.text) #獲取字符串類型的響應(yīng)內(nèi)容
print(response.body)#獲取字節(jié)類型的相應(yīng)內(nèi)容
View Code
設(shè)置修改settings.py配置文件相關(guān)配置
# settings.py 文件中
#不遵從robots協(xié)議
#進(jìn)行UA偽裝
#進(jìn)行日志等級設(shè)定: LOG_LEVEL = False
View Code
setting.py中 ----- 基于終端指令的持久化存儲操作
BOT_NAME = 'firstBlood' SPIDER_MODULES = ['firstBlood.spiders'] NEWSPIDER_MODULE = 'firstBlood.spiders' # Crawl responsibly by identifying yourself (and your website) on the user-agent USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36' #進(jìn)行ua偽裝 # Obey robots.txt rules ROBOTSTXT_OBEY = False #不遵從robotstx協(xié)議 LOG_LEVEL = 'ERROR' #輸出錯誤類型的日志
View Code
setting.py ------------- 基于管道的持久化存儲
BOT_NAME = 'qiubaiPro'
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'
SPIDER_MODULES = ['qiubaiPro.spiders']
NEWSPIDER_MODULE = 'qiubaiPro.spiders'
ITEM_PIPELINES = {
'qiubaiPro.pipelines.QiubaiproPipeline': 300, #300表示的是優(yōu)先級(數(shù)值越小優(yōu)先級越大)
}
View Code
執(zhí)行爬蟲程序:scripy crawl spiderName
不輸出日志(錯誤信息會在日志中輸出,不要使用)
scripy crawl spiderName --nolog
View Code
7.2.3scrapy框架持久化存儲
#持久化存儲
#基于終端指令
特性 : 只能將 parse 方法的返回值存儲到本地的磁盤文件中
指令 : scripy crawl spiderName -o filepath
#基于管道
#實現(xiàn)流程
1.數(shù)據(jù)解析
2.在item類中定義相關(guān)屬性
3.將解析的數(shù)據(jù)封裝到一個 item 對象中(item文件中對應(yīng)類的對象)
4.向管道提交item
5.在管道文件中的 process_item 方法中接收 item 進(jìn)行持久化存儲
6.在配置文件中開啟管道
#管道中需注意細(xì)節(jié):
1.配置文件中開啟的管道是一個字典,字典中的鍵值表示的就是某一個管道
2.在管道對應(yīng)的源文件中其實可以定義多個管道類,一種形式的持久化存儲
3.在process_item方法中的 return item 表示的是提交給下一個即將被執(zhí)行的管道類
4.爬蟲文件中yield item 只可以將item傳遞給第一個被執(zhí)行的(優(yōu)先級最高的)管道
#將同一份數(shù)據(jù)持久化存儲到不同平臺中:
#分析
1.管道文件中的一個管道內(nèi)負(fù)責(zé)數(shù)據(jù)的一種形式的持久化存儲
setting.py中 ----- 基于終端指令的持久化存儲操作
BOT_NAME = 'firstBlood' SPIDER_MODULES = ['firstBlood.spiders'] NEWSPIDER_MODULE = 'firstBlood.spiders' # Crawl responsibly by identifying yourself (and your website) on the user-agent USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36' #進(jìn)行ua偽裝 # Obey robots.txt rules ROBOTSTXT_OBEY = False #不遵從robotstx協(xié)議 LOG_LEVEL = 'ERROR' #輸出錯誤類型的日志
View Code
setting.py ------------- 基于管道的持久化存儲
BOT_NAME = 'qiubaiPro'
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'
SPIDER_MODULES = ['qiubaiPro.spiders']
NEWSPIDER_MODULE = 'qiubaiPro.spiders'
ITEM_PIPELINES = {
'qiubaiPro.pipelines.QiubaiproPipeline': 300, #300表示的是優(yōu)先級(數(shù)值越小優(yōu)先級越大)
}
View Code
糗事百科
qiubai.py
import scrapy
from qiubaiPro.items import QiubaiproItem
class QiubaiSpider(scrapy.Spider):
name = 'qiubai'
# allowed_domains = ['http://t.zoukankan.com/www.xxx.com']
start_urls = ['https://www.qiushibaike.com/text/']
#基于終端指令的持久化存儲操作
# def parse(self, response):
# div_list = response.xpath('//*[@id="content-left"]/div')
# all_data = []
# for div in div_list:
# #scrapy中的xpath返回的列表的列表元素一定是Selector對象,我們最終想要的解析的
# #數(shù)據(jù)一定是存儲在該對象中
# #extract()將Selector對象中data參數(shù)的值取出
# # author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
# author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
# #列表直接調(diào)用extract表示的是將extract作用到每一個列表元素中
# content = div.xpath('./a[1]/div/span//text()').extract()
# content = ''.join(content)
# dic = {
# 'author':author,
# 'content':content
# }
# all_data.append(dic)
# return all_data
#基于管道的持久化存儲
def parse(self, response):
div_list = response.xpath('//*[@id="content-left"]/div')
all_data = []
for div in div_list:
#scrapy中的xpath返回的列表的列表元素一定是Selector對象,我們最終想要的解析的
#數(shù)據(jù)一定是存儲在該對象中
#extract()將Selector對象中data參數(shù)的值取出
# author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
#列表直接調(diào)用extract表示的是將extract作用到每一個列表元素中
content = div.xpath('./a[1]/div/span//text()').extract()
content = ''.join(content)
#將解析的數(shù)據(jù)存儲到item對象
item = QiubaiproItem()
item['author'] = author
item['content'] = content
#將item提交給管道
yield item #item一定是提交給了優(yōu)先級最高的管道類
View Code
itims.py
import scrapy
class QiubaiproItem(scrapy.Item):
# define the fields for your item here like:
author = scrapy.Field() #Field可以將其理解成是一個萬能的數(shù)據(jù)類型
content = scrapy.Field()
View Code
pipelines.py 管道文件
import pymysql
from redis import Redis
class QiubaiproPipeline(object):
fp = None
def open_spider(self,spider):
print('開始爬蟲......')
self.fp = open('qiushibaike.txt','w',encoding='utf-8')
#使用來接收爬蟲文件提交過來的item,然后將其進(jìn)行任意形式的持久化存儲
#參數(shù)item:就是接收到的item對象
#該方法每接收一個item就會調(diào)用一次
def process_item(self, item, spider):
author = item['author']
content= item['content']
self.fp.write(author+':'+content+'
')
return item #item是返回給了下一個即將被執(zhí)行的管道類
def close_spider(self,spider):
print('結(jié)束爬蟲!')
self.fp.close()
#負(fù)責(zé)將數(shù)據(jù)存儲到mysql
class MysqlPL(object):
conn = None
cursor = None
def open_spider(self,spider):
self.conn = pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='123',db='spider',charset='utf8')
print(self.conn)
def process_item(self,item,spider):
author = item['author']
content = item['content']
sql = 'insert into qiubai values ("%s","%s")'%(author,content)
self.cursor = self.conn.cursor()
try:
self.cursor.execute(sql)
self.conn.commit()
except Exception as e:
print(e)
self.conn.rollback()
return item
def close_spider(self,spider):
self.cursor.close()
self.conn.close()
#基于redis的管道存儲
class RedisPL(object):
conn = None
def open_spider(self,spider):
self.conn = Redis(host='127.0.0.1',port=6379)
print(self.conn)
def process_item(self,item,spider):
self.conn.lpush('all_data',item) # name value
#注意:如果將字典寫入redis報錯:pip install -U redis==2.10.6
View Code
7.2.4scrapy框架之遞歸解析和post請求
遞歸解析(手動請求發(fā)送)
使用場景 :爬取多個頁碼對應(yīng)的頁面源碼數(shù)據(jù)
yield scrapy.Request(url,callback)
import scrapy
from qiubaiPro.items import QiubaiproItem
class QiubaiSpider(scrapy.Spider):
name = 'qiubai'
# allowed_domains = ['http://t.zoukankan.com/www.xxx.com']
start_urls = ['https://www.qiushibaike.com/text/']
#將多個頁碼對應(yīng)的頁面數(shù)據(jù)進(jìn)行爬取和解析的操作
url = 'https://www.qiushibaike.com/text/page/%d/'#通用的url模板
pageNum = 1
#parse第一次調(diào)用表示的是用來解析第一頁對應(yīng)頁面中的段子內(nèi)容和作者
def parse(self, response):
div_list = response.xpath('//*[@id="content-left"]/div')
all_data = []
for div in div_list:
# scrapy中的xpath返回的列表的列表元素一定是Selector對象,我們最終想要的解析的
# 數(shù)據(jù)一定是存儲在該對象中
# extract()將Selector對象中data參數(shù)的值取出
# author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
# 列表直接調(diào)用extract表示的是將extract作用到每一個列表元素中
content = div.xpath('./a[1]/div/span//text()').extract()
content = ''.join(content)
# 將解析的數(shù)據(jù)存儲到item對象
item = QiubaiproItem()
item['author'] = author
item['content'] = content
# 將item提交給管道
yield item # item一定是提交給了優(yōu)先級最高的管道類
if self.pageNum <= 5:
self.pageNum += 1
new_url = format(self.url%self.pageNum)
#手動請求(get)的發(fā)送
yield scrapy.Request(new_url,callback=self.parse)
View Code
post請求發(fā)送
問題:在之前代碼中,我們從來沒有手動的對start_urls列表中存儲的起始url進(jìn)行過請求的發(fā)送,但是起始url的確是進(jìn)行了請求的發(fā)送,那這是如何實現(xiàn)的呢?
解答:其實是因為爬蟲文件中的爬蟲類繼承到了Spider父類中的start_requests(self)這個方法,該方法就可以對start_urls列表中的url發(fā)起請求:
def start_requests(self):
for u in self.start_urls:
yield scrapy.Request(url=u,callback=self.parse)
【注意】該方法默認(rèn)的實現(xiàn),是對起始的url發(fā)起get請求,如果想發(fā)起post請求,則需要子類重寫該方法。
方法: 重寫start_requests方法,讓其發(fā)起post請求:
def start_requests(self):
#請求的url
post_url = 'http://fanyi.baidu.com/sug'
# post請求參數(shù)
formdata = {
'kw': 'wolf',
}
# 發(fā)送post請求
yield scrapy.FormRequest(url=post_url, formdata=formdata, callback=self.parse)
scrapy五大核心組件
#引擎(Scrapy) 用來處理整個系統(tǒng)的數(shù)據(jù)流處理, 觸發(fā)事務(wù)(框架核心) #調(diào)度器(Scheduler) 用來接受引擎發(fā)過來的請求, 壓入隊列中, 并在引擎再次請求的時候返回. 可以想像成一個URL(抓取網(wǎng)頁的網(wǎng)址或者說是鏈接)的優(yōu)先隊列, 由它來決定下一個要抓取的網(wǎng)址是什么, 同時去除重復(fù)的網(wǎng)址 #下載器(Downloader) 用于下載網(wǎng)頁內(nèi)容, 并將網(wǎng)頁內(nèi)容返回給蜘蛛(Scrapy下載器是建立在twisted這個高效的異步模型上的) #爬蟲(Spiders) 爬蟲是主要干活的, 用于從特定的網(wǎng)頁中提取自己需要的信息, 即所謂的實體(Item)。用戶也可以從中提取出鏈接,讓Scrapy繼續(xù)抓取下一個頁面 #項目管道(Pipeline) 負(fù)責(zé)處理爬蟲從網(wǎng)頁中抽取的實體,主要的功能是持久化實體、驗證實體的有效性、清除不需要的信息。當(dāng)頁面被爬蟲解析后,將被發(fā)送到項目管道,并經(jīng)過幾個特定的次序處理數(shù)據(jù)。
工作流程
#步驟 1.spider中的url被封裝成請求對象交給引擎(每一個url對應(yīng)一個請求對象); 2.引擎拿到請求對象之后, 將其全部交給調(diào)度器; 3.調(diào)度器拿到所有請求對象后, 通過內(nèi)部的過濾器過濾掉重復(fù)的url, 最后將去重后的所有url對應(yīng)的請求對象壓入到隊列中, 隨后調(diào)度器調(diào)度出其中一個請求對象, 并將其交給引擎; 4.引擎將調(diào)度器調(diào)度出的請求對象交給下載器; 5.下載器拿到該請求對象去互聯(lián)網(wǎng)中下載數(shù)據(jù); 6.數(shù)據(jù)下載成功后會被封裝到response中, 隨后response會被交給下載器; 7.下載器將response交給引擎; 8.引擎將response交給spiders; 9.spiders拿到response后調(diào)用回調(diào)方法進(jìn)行數(shù)據(jù)解析, 解析成功后產(chǎn)生item, 隨后spiders將item交給引擎; 10.引擎將item交給管道, 管道拿到item后進(jìn)行數(shù)據(jù)的持久化存儲.
7.3基于scrapy進(jìn)行圖片數(shù)據(jù)的爬取
示例 :校花網(wǎng)圖片的爬取
鏈接地址 :http://www.521609.com/daxuemeinv/list81.html
項目的創(chuàng)建
scrapy startproject imgPro
cd imgPro
scrapy genspider img http://t.zoukankan.com/www.xxx.com
如何基于scrapy進(jìn)行圖片的爬取
1.在爬蟲文件中只需要解析出圖片地址,然后將圖片地址提交給管道
2.配置文件中添加 IMAGES_STORE = './imasLib'
1.在管道文件中進(jìn)行管道類的制定:
from scrapy.pipelines.images import ImagesPipeline
將管道的父類修改成 ImagesPipeline
重寫父類的三個方法
代碼:
img.py
import scrapy
from imgPro.items import ImgproItem
class ImgSpider(scrapy.Spider):
name = 'img'
# allowed_domains = ['www.x.com']
start_urls = ['http://www.521609.com/daxuemeinv/']
url = 'http://www.521609.com/daxuemeinv/list8%d.html'
pageNum = 1
def parse(self, response):
li_list = response.xpath('//*[@id="content"]/div[2]/div[2]/ul/li')
for li in li_list:
img_src = 'http://www.521609.com' + li.xpath('./a[1]/img/@src').extract_first()
item = ImgproItem()
item['src'] = img_src
yield item
if self.pageNum < 4:
self.pageNum += 1
new_url = format(self.url%self.pageNum)
yield scrapy.Request(new_url,callback=self.parse)
View Code
setting.py
##不遵從robotstx協(xié)議
ROBOTSTXT_OBEY = False
#輸出錯誤類型的日志
LOG_LEVEL = 'ERROR'
# LOG_FILE = './log.txt'
#圖片存儲地址
IMAGES_STORE = './imasLib'
ITEM_PIPELINES = {
'imgPro.pipelines.ImgproPipeline': 300,
}
View Code
pipelines.py
import scrapy
from scrapy.pipelines.images import ImagesPipeline
class ImgproPipeline(ImagesPipeline):
#對某一個媒體資源進(jìn)行請求發(fā)送
# item 就是接收到的spider提交的數(shù)據(jù)
def get_media_requests(self, item, info):
yield scrapy.Request(item['src'])
#指定媒體數(shù)據(jù)存儲的名稱
def file_path(self, request, response=None, info=None):
#返回原始圖片名稱
name = request.url.split('/')[-1]
print("正在下載:",name)
return name
#將 item 傳遞給下一個即將被執(zhí)行的管道類
def item_completed(self, results, item, info):
return item
View Code
items.py
import scrapy
class ImgproItem(scrapy.Item):
# define the fields for your item here like:
src = scrapy.Field()
View Code
如何提升scrapy爬取數(shù)據(jù)的效率
只需要將如下五個步驟配置在配置文件中即可:
#增加并發(fā)
默認(rèn)scrapy開啟的并發(fā)線程為32個,可以適當(dāng)進(jìn)行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100值為100,并發(fā)設(shè)置成了為100。
#降低日志級別:
在運行scrapy時,會有大量日志信息的輸出,為了減少CPU的使用率。可以設(shè)置log輸出信息為INFO或者ERROR即可。在配置文件中編寫:LOG_LEVEL = ‘INFO’
#禁止cookie:
如果不是真的需要cookie,則在scrapy爬取數(shù)據(jù)時可以禁止cookie從而減少CPU的使用率,提升爬取效率。在配置文件中編寫:COOKIES_ENABLED = False
#禁止重試:
對失敗的HTTP進(jìn)行重新請求(重試)會減慢爬取速度,因此可以禁止重試。在配置文件中編寫:RETRY_ENABLED = False
#減少下載超時:
如果對一個非常慢的鏈接進(jìn)行爬取,減少下載超時可以能讓卡住的鏈接快速被放棄,從而提升效率。在配置文件中進(jìn)行編寫:DOWNLOAD_TIMEOUT = 10 超時時間為10s
7.4請求傳參
實現(xiàn)深度爬取:爬取多個層級對應(yīng)的頁面數(shù)據(jù)
使用場景:爬取的數(shù)據(jù)沒有在同一張頁面中
在手動請求的時候傳遞item:yield scrapy.Request(url,callback,meta={'item':item})
將meta這個字典傳遞給callback
在callback中接收meta:item = response.meta['item']
代碼:
movie.py
import scrapy
from moviePro.items import MovieproItem
class MovieSpider(scrapy.Spider):
name = 'movie'
# allowed_domains = ['http://t.zoukankan.com/www.xxx.com']
start_urls = ['https://www.4567tv.tv/index.php/vod/show/class/動作/id/5.html']
url = 'https://www.4567tv.tv/index.php/vod/show/class/動作/id/5/page/%d.html'
pageNum = 1
def parse(self, response):
li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li')
for li in li_list:
title = li.xpath('./div[1]/a/@title').extract_first()
detail_url = "https://www.4567tv.tv" + li.xpath('./div[1]/a/@href').extract_first()
item = MovieproItem()
item['title'] = title
# meta參數(shù)是一個字典,該參數(shù)可以傳遞給callback指定的回調(diào)函數(shù),
yield scrapy.Request(detail_url,callback=self.parse_detail,meta={'item':item})
if self.pageNum < 5:
self.pageNum += 1
new_url = format(self.url%self.pageNum)
yield scrapy.Request(new_url,callback=self.parse)
def parse_detail(self,response):
#接收參數(shù) response.meta
item = response.meta['item']
#簡介
desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
item['desc'] = desc
yield item
View Code
setting.py
BOT_NAME = 'moviePro'
SPIDER_MODULES = ['moviePro.spiders']
NEWSPIDER_MODULE = 'moviePro.spiders'
# UA偽裝
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
#輸出錯誤類型的日志
LOG_LEVEL = 'ERROR'
ITEM_PIPELINES = {
'moviePro.pipelines.MovieproPipeline': 300,
}
View Code
items.py
import scrapy
class MovieproItem(scrapy.Item):
# define the fields for your item here like:
title = scrapy.Field()
desc = scrapy.Field()
View Code
pipelines.py
class MovieproPipeline(object):
def process_item(self, item, spider):
print(item)
return item
View Code
7.5scrapy中的中間件的應(yīng)用
1.請求載體身份標(biāo)識(可用)
user_agent_list = [
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 "
"(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 "
"(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 "
"(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 "
"(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 "
"(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 "
"(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 "
"(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 "
"(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 "
"(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
]
View Code
3.代理池(不可用)
PROXY_http = [
'153.180.102.104:80',
'195.208.131.189:56055',
]
PROXY_https = [
'120.83.49.90:9000',
'95.189.112.214:35508',
]
View Code
3.爬蟲中間件
4.下載中間件
作用 :批量攔截請求和響應(yīng)
攔截請求
UA偽裝 :將所有的請求盡可能多的設(shè)定成不同的請求載體身份標(biāo)識
代理操作
rom scrapy import signals
import random
user_agent_list = [
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 "
"(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 "
"(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 "
"(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 "
"(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 "
"(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 "
"(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 "
"(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
"(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 "
"(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 "
"(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
]
PROXY_http = [
'153.180.102.104:80',
'195.208.131.189:56055',
]
PROXY_https = [
'120.83.49.90:9000',
'95.189.112.214:35508',
]
# 下載中間件
class MovieproDownloaderMiddleware(object):
# 攔截正常的請求,參數(shù) request 就是攔截到請求對象
def process_request(self, request, spider):
print("i am process_request")
#實現(xiàn):將攔截到的請求盡可能多的設(shè)定成不同的請求載體身份標(biāo)識
request.headers['USER_AGENT'] = random.choice(user_agent_list)
if request.url.split(":")[0] == "http":
request.meta['proxy'] = 'http://' + random.choice(PROXY_http)
else:
request.meta['proxy'] = 'https://' + random.choice(PROXY_https)
return None
# 攔截響應(yīng),參數(shù) request 就是攔截到響應(yīng)
def process_response(self, request, response, spider):
print("i am process_response")
return response
# 攔截發(fā)生異常的請求
def process_exception(self, request, exception, spider):
print("i am process_exception")
#攔截到異常的請求,然后對其進(jìn)行修正,然后重新進(jìn)行請求發(fā)送
#代理操作
if request.url.split(":")[0] == "http":
request.meta['proxy'] = 'http://' + random.choice(PROXY_http)
else:
request.meta['proxy'] = 'https://' + random.choice(PROXY_https)
#將修正后的請求進(jìn)行重新發(fā)送
return request
View Code
攔截響應(yīng)
篡改響應(yīng)數(shù)據(jù)或直接替換響應(yīng)對象
需求 : 爬取網(wǎng)易新聞 國內(nèi),國際,軍事,航空,無人機(jī)這五個板塊下對應(yīng)的新聞標(biāo)題和內(nèi)容
#分析:
1.每一個板塊對應(yīng)的新聞數(shù)據(jù)是動態(tài)加載出來的
# selenium在scrapy中的應(yīng)用:
實例化瀏覽器對象:卸載爬蟲類的構(gòu)造方法中
wangyi.py
import scrapy
from selenium import webdriver
from wangyiPro.items import WangyiproItem
class WangyiSpider(scrapy.Spider):
name = 'wangyi'
# allowed_domains = ['http://t.zoukankan.com/www.xxx.com']
start_urls = ['https://news.163.com']
five_model_urls = []
#實例化一個瀏覽器對象
bro = webdriver.Chrome(executable_path=r'E:飛秋爬蟲+數(shù)據(jù) oolschromedriver.exe')
#用來解析五個板塊對應(yīng)的url,然后對齊進(jìn)行手動請求發(fā)送
def parse(self, response):
model_index = [3,4,6,7,8]
li_list = response.xpath('//*[@id="index2016_wrap"]/div[1]/div[2]/div[2]/div[2]/div[2]/div/ul/li')
for index in model_index:
li = li_list[index]
#獲取五個板塊對應(yīng)的url
model_url = li.xpath('./a/@href').extract_first()
self.five_model_urls.append(model_url)
#對每個板塊的url進(jìn)行手動請求發(fā)送
yield scrapy.Request(model_url,callback=self.parse_model)
#用作與解析每個板塊中的新聞標(biāo)題和新聞詳情頁的url
#問題:response(不滿足需求的response)沒有包含每一個板塊中動態(tài)加載的新聞數(shù)據(jù)
def parse_model(self,response):
div_list = response.xpath('/html/body/div/div[3]/div[4]/div[1]/div/div/ul/li/div/div')
for div in div_list:
title = div.xpath('./div/div[1]/h3/a/text()').extract_first()
detail_url = div.xpath('./div/div[1]/h3/a/@href').extract_first()
item = WangyiproItem()
item['title'] = title
#對詳情頁發(fā)起請求解析出新聞內(nèi)容
yield scrapy.Request(detail_url,callback=self.prase_new_detail,meta={'item':item})
def prase_new_detail(self,response):
item = response.meta['item']
content = response.xpath('//*[@id="endText"]//text()').extract()
content = ''.join(content)
item['content'] = content
yield item
#最后執(zhí)行
def closed(self,spider):
self.bro.quit()
View Code
items.py
import scrapy
class WangyiproItem(scrapy.Item):
# define the fields for your item here like:
title = scrapy.Field()
content = scrapy.Field()
View Code
middlewares.py
from scrapy import signals
from scrapy.http import HtmlResponse
from time import sleep
class WangyiproDownloaderMiddleware(object):
def process_request(self, request, spider):
return None
# spider 就是爬蟲文件中爬蟲類實例化的對象
def process_response(self, request, response, spider):
#進(jìn)行所有響應(yīng)對象的攔截
# 1.將所有響應(yīng)對象中那五個不滿足需求的響應(yīng)對象找出
#每個響應(yīng)對象對應(yīng)唯一一個請求對象
#如果我們定位到五個響應(yīng)對象的請求對象后,就可以通過該請求對象定位到指定的響應(yīng)對象
#可以通過五個板塊的 url 定位請求對象
#總結(jié): url ==> request ==> response
# 2.將找出的五個不滿足需求的響應(yīng)對象進(jìn)行修正(替換)
# spider.five_model_urls :五個板塊對應(yīng)的url
bro = spider.bro
if request.url in spider.five_model_urls:
bro.get(request.url)
sleep(1)
#包含了動態(tài)加載的新聞數(shù)據(jù)
page_text = bro.page_source
#如果if條件成立,則該response就是五個板塊對應(yīng)的響應(yīng)對象
new_response = HtmlResponse(url=request.url,body=page_text,encoding='utf-8',request=request)
return new_response
return response
def process_exception(self, request, exception, spider):
pass
View Code
pipelines.py
class WangyiproPipeline(object):
def process_item(self, item, spider):
print(item)
return item
View Code
setting.py
BOT_NAME = 'wangyiPro'
SPIDER_MODULES = ['wangyiPro.spiders']
NEWSPIDER_MODULE = 'wangyiPro.spiders'
# UA偽裝
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'
ROBOTSTXT_OBEY = False
LOG_LEVEL = 'ERROR'
DOWNLOADER_MIDDLEWARES = {
'wangyiPro.middlewares.WangyiproDownloaderMiddleware': 543,
}
ITEM_PIPELINES = {
'wangyiPro.pipelines.WangyiproPpeline': 300,
}
View Code
7.6.基于CrawSpider的全站數(shù)據(jù)爬取
CrawSpider簡介
CrawSpider就是爬蟲類中 Spider的一個子類
除了繼承到Spider的特性和功能外,還派生除了其自己獨有的更加強(qiáng)大的特性和功能。其中最顯著的功能就是”LinkExtractors鏈接提取器“。Spider是所有爬蟲的基類,其設(shè)計原則只是為了爬取start_url列表中網(wǎng)頁,而從爬取到的網(wǎng)頁中提取出的url進(jìn)行繼續(xù)的爬取工作使用CrawlSpider更合適。
使用流程
1.創(chuàng)建一個基于CrawSpider的爬蟲文件 :
scrapy startproject sunPro
cd sunPro
scrapy genspider -t crawl spiderName http://t.zoukankan.com/www.xxx.com
2.構(gòu)造鏈接提取器和規(guī)則解析器
鏈接提取器
作用:可根據(jù)指定的規(guī)則進(jìn)行指定鏈接的提取
提取規(guī)則:allow = '正則表達(dá)式'
規(guī)則解析器
作用:獲取鏈接提取器提取到的鏈接,然后進(jìn)行請求發(fā)送,根據(jù)指定規(guī)則對請求到的頁面源碼數(shù)據(jù)進(jìn)行數(shù)據(jù)解析
follow = 'True' :將鏈接提取器 繼續(xù)作用到 鏈接提取器所提取到的頁碼鏈接所對應(yīng)的頁面中
7.6.1 基于CrawSpider的基本使用
數(shù)據(jù)鏈接地址 :http://wz.sun0769.com/index.php/question/questionType?type=4&page=
sun.py
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
#未實現(xiàn)深度爬取:爬取的只是每個頁面對應(yīng)的數(shù)據(jù)
class SunSpider(CrawlSpider):
name = 'sun'
# allowed_domains = ['http://t.zoukankan.com/www.xxx.com']
start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=']
#鏈接提取器 type=4&page=d+
link = LinkExtractor(allow=r'type=4&page=d+')
rules = (
#實例化一個Rule(規(guī)則解析器)的對象
Rule(link, callback='parse_item', follow=True),
)
def parse_item(self, response):
tr_list = response.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr')
for tr in tr_list:
title = tr.xpath('./td[2]/a[2]/@title').extract_first()
status = tr.xpath('./td[3]/span/text()').extract_first()
print(title,status)
View Code
setting.py
BOT_NAME = 'sunPro' SPIDER_MODULES = ['sunPro.spiders'] NEWSPIDER_MODULE = 'sunPro.spiders' # UA偽裝 USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36' ROBOTSTXT_OBEY = False LOG_LEVEL = 'ERROR'
View Code
7.6.2 基于CrawSpider的深度爬取
sun.py
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from sunPro.items import SunproItem,SunproItem_detail
class SunSpider(CrawlSpider):
name = 'sun'
# allowed_domains = ['http://t.zoukankan.com/www.xxx.com']
start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=']
#鏈接提取器
link = LinkExtractor(allow=r'type=4&page=d+')
#詳情頁url question/201909/426989.shtml
link_detail = LinkExtractor(allow=r'question/d+/d+.shtml')
rules = (
#實例化一個Rule(規(guī)則解析器)的對象
Rule(link, callback='parse_item', follow=True),
Rule(link_detail, callback='parse_datail'),
)
def parse_item(self, response):
tr_list = response.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr')
for tr in tr_list:
title = tr.xpath('./td[2]/a[2]/@title').extract_first()
status = tr.xpath('./td[3]/span/text()').extract_first()
num = tr.xpath('./td[1]/text()').extract_first()
item = SunproItem()
item['title'] = title
item['status'] = status
item['num'] = num
if num:
yield item
def parse_datail(self,response):
content = response.xpath('/html/body/div[9]/table[2]/tbody/tr[1]//text()').extract()
content = ''.join(content)
num = response.xpath('/html/body/div[9]/table[1]/tbody/tr/td[2]/span[2]/text()').extract_first()
if num:
num = num.split(':')[-1]
item = SunproItem_detail()
item['content'] = content
item['num'] = num
yield item
View Code
pipelines.py
class SunproPipeline(object):
def process_item(self, item, spider):
if item.__class__.__name__ == "SunproItem_detail":
content = item['content']
num = item['num']
print(content,num)
else:
title = item['title']
status = item['status']
num = item['num']
print(title,status,num)
View Code
items.py
class SunproItem(scrapy.Item):
title = scrapy.Field()
status = scrapy.Field()
num = scrapy.Field()
class SunproItem_detail(scrapy.Item):
content = scrapy.Field()
num = scrapy.Field()
View Code
7.7.分布式
7.7.1基本概念
什么是分布式爬蟲?
基于多臺電腦組建一個分布式機(jī)群,然后讓機(jī)群中的每一臺電腦執(zhí)行同一組程序,然后讓它們對同一個網(wǎng)站的數(shù)據(jù)進(jìn)行分布爬取
為什么要用分布式爬蟲?
提升爬取數(shù)據(jù)的效率
如何實現(xiàn)分布式爬蟲?
基于scrapy + redis 的形式實現(xiàn)分布式
scrapy 結(jié)合著 scrapy-redis組件實現(xiàn)分布式
原生的scrapy無法實現(xiàn)分布式原因?
調(diào)度器無法被分布式群共享
管道無法被共享
scrapy-redis組件的作用
提供可以被共享的調(diào)度器和管道
環(huán)境安裝:
pip insatll redis
pip install scrapy-redis
7.7.2分布式流程
#1.創(chuàng)建一個基于CrawSpider的爬蟲文件 :
scrapy startproject sunPro
cd sunPro
scrapy genspider -t crawl spiderName http://t.zoukankan.com/www.xxx.com
#2.修改當(dāng)前的爬蟲文件
1.導(dǎo)包 : from scrapy_redis.spiders import RedisCrawlSpider
2.將當(dāng)前爬蟲類的父類修改成RedisCrawlSpider
3.將start_urls替換成redis_key = 'xxx' #表示的是可被共享調(diào)度器中隊列的名稱
4.編寫爬蟲類爬取數(shù)據(jù)的操作
#3.對setting進(jìn)行操作
#指定管道
開啟可被共享的管道 :
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 400
}
#指定可被共享的調(diào)度器
# 增加了一個去重容器類的配置, 作用使用Redis的set集合來存儲請求的指紋數(shù)據(jù), 從而實現(xiàn)請求去重的持久化
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis組件自己的調(diào)度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 配置調(diào)度器是否要持久化, 也就是當(dāng)爬蟲結(jié)束了, 要不要清空Redis中請求隊列和去重指紋的set。如果是True, 就表示要持久化存儲, 就不清空數(shù)據(jù), 否則清空數(shù)據(jù)
SCHEDULER_PERSIST = True
#指定redis服務(wù)
REDIS_HOST = 'redis服務(wù)的ip地址'
REDIS_PORT = 6379
#4.對redis配置文件進(jìn)行配置 (redis.windows.conf)
56行 : #bind 127.0.0.1
75行 : protected-mode yes --> protected-mode no
#5.攜帶配置文件啟動redis服務(wù) redis-server .edis.windows.conf
地址: E:飛秋爬蟲+數(shù)據(jù) oolsedisRedis-x64-3.2.100
#6.啟動redis客戶端 : redis-cli
#7.執(zhí)行當(dāng)前的工程
進(jìn)入到爬蟲文件對應(yīng)的目錄中:scrapy runspider xxx.py
#8.向調(diào)度器隊列中仍入一個起始的url:
隊列在哪里呢?
答:隊列在redis中 lpush fbsQueue http://t.zoukankan.com/www.xxx.com
代碼
fbs.py
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_redis.spiders import RedisCrawlSpider
from fbsPro.items import FbsproItem
class FbsSpider(RedisCrawlSpider):
name = 'fbs'
# allowed_domains = ['http://t.zoukankan.com/www.xxx.com']
# start_urls = ['http://http://t.zoukankan.com/www.xxx.com/']
# redis_key表示的是可被共享調(diào)度器中隊列的名稱
redis_key = 'fbsQueue'
rules = (
Rule(LinkExtractor(allow=r'type=4&page=d+'), callback='parse_item', follow=True),
)
def parse_item(self, response):
tr_list = response.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr')
for tr in tr_list:
title = tr.xpath('./td[2]/a[2]/@title').extract_first()
status = tr.xpath('./td[3]/span/text()').extract_first()
item = FbsproItem()
item['title'] = title
item['status'] = status
yield item
View Code
items.py
import scrapy
class FbsproItem(scrapy.Item):
title = scrapy.Field()
status = scrapy.Field()
View Code
settings.py
BOT_NAME = 'fbsPro'
SPIDER_MODULES = ['fbsPro.spiders']
NEWSPIDER_MODULE = 'fbsPro.spiders'
ROBOTSTXT_OBEY = True
#開啟可被共享的管道
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 400
}
#指定可被共享的調(diào)度器
# 增加了一個去重容器類的配置, 作用使用Redis的set集合來存儲請求的指紋數(shù)據(jù), 從而實現(xiàn)請求去重的持久化
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis組件自己的調(diào)度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 配置調(diào)度器是否要持久化, 也就是當(dāng)爬蟲結(jié)束了, 要不要清空Redis中請求隊列和去重指紋的set。如果是True, 就表示要持久化存儲, 就不清空數(shù)據(jù), 否則清空數(shù)據(jù)
SCHEDULER_PERSIST = True
#指定redis服務(wù)
REDIS_HOST = '192.168.11.50'
REDIS_PORT = 6379
View Code
7.8 增量式爬蟲
總結(jié)
以上是生活随笔為你收集整理的python爬虫入门 之 移动端数据的爬取的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 转 15款免费WiFi(入侵破解)安全测
- 下一篇: 触发OSR 编译(以goto指令为例)及