柚子快報(bào)邀請(qǐng)碼778899分享:pyhton-8-scrapy
柚子快報(bào)邀請(qǐng)碼778899分享:pyhton-8-scrapy
scrapy
scrapy安裝scrapy項(xiàng)目的創(chuàng)建以及運(yùn)行scrapy架構(gòu)組成scrapy工作原理scrapy shellyieldMysqlpymysql的使用步驟CrawlSpider
scrapy安裝
點(diǎn)我學(xué)習(xí)scrapy的安裝
1. scrapy是什么?
Scrapy是一個(gè)為了爬取網(wǎng)站數(shù)據(jù),提取結(jié)構(gòu)性數(shù)據(jù)而編寫(xiě)的應(yīng)用框架。 可以應(yīng)用在包括數(shù)據(jù)挖掘,信息處理或存儲(chǔ)歷史數(shù)據(jù)等一系列的程序中。
2. 安裝scrapy:
pip install scrapy
安裝過(guò)程中出錯(cuò):
如果安裝有錯(cuò)誤?。。?!
pip install Scrapy
building 'twisted.test.raiser' extension
error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++
Build Tools": http://landinghub.visualstudio.com/visual‐cpp‐build‐tools
解決方案:
http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
下載twisted對(duì)應(yīng)版本的whl文件(如我的Twisted‐17.5.0‐cp36‐cp36m‐win_amd64.whl),cp后面是
python版本,amd64代表64位,運(yùn)行命令:
pip install C:\Users\...\Twisted‐17.5.0‐cp36‐cp36m‐win_amd64.whl
pip install Scrapy
如果再報(bào)錯(cuò)
python ‐m pip install ‐‐upgrade pip
如果再報(bào)錯(cuò) win32
解決方法:
pip install pypiwin32
再報(bào)錯(cuò):使用anaconda
使用步驟:
打開(kāi)anaconda
點(diǎn)擊environments
點(diǎn)擊not installed
輸入scrapy
apply
在pycharm中選擇anaconda的環(huán)境
scrapy項(xiàng)目的創(chuàng)建以及運(yùn)行
3. 創(chuàng)建scrapy項(xiàng)目:
終端輸入 scrapy startproject 項(xiàng)目名稱
注意:
項(xiàng)目的名字不允許使用數(shù)字開(kāi)頭 也不能包含中文要在spiders文件夾中創(chuàng)建爬蟲(chóng)文件cd 項(xiàng)目的名字\項(xiàng)目的名字\spiders
創(chuàng)建爬蟲(chóng)文件
scrapy genspier 爬蟲(chóng)的文件名 要爬取的網(wǎng)頁(yè)
eg: scrapy genspider baidu http://baidu.com
運(yùn)行爬蟲(chóng)代碼
scrapy crawl 爬蟲(chóng)的名字
eg:
scrapy crawl baidu
在運(yùn)行前我們需要把setting中的君子協(xié)議給注釋掉,如下圖
這是各個(gè)瀏覽器之間的協(xié)議,我們不需要遵守 我們將紅圈中的內(nèi)容將其注釋掉
import scrapy
class BaiduSpider(scrapy.Spider):
#爬蟲(chóng)的名字,運(yùn)行爬蟲(chóng)的時(shí)候 使用的值
name = "baidu"
#允許訪問(wèn)的域名
allowed_domains = ["www.baidu.com"]
#起始的url地址 指的是第一次訪問(wèn)的域名
#start_urls是在allowed_domains前面添加http://
start_urls = ["http://www.baidu.com"]
#是執(zhí)行了start_urls之后 執(zhí)行的方法 方法中的response 就是返回的那個(gè)對(duì)象
#相當(dāng)于 response=urllib.request.urlopen()
# response=request.get()
def parse(self, response):
print('這是一個(gè)測(cè)試')
4. 項(xiàng)目組成:
scrapy項(xiàng)目的結(jié)構(gòu)
項(xiàng)目名字
項(xiàng)目名字
spiders
__init__.py
自定義的爬蟲(chóng)文件.py ‐‐‐》由我們自己創(chuàng)建,是實(shí)現(xiàn)爬蟲(chóng)核心功能的文件
__init__.py
items.py ‐‐‐》定義數(shù)據(jù)結(jié)構(gòu)的地方,是一個(gè)繼承自scrapy.Item的類
middlewares.py ‐‐‐》中間件 代理
pipelines.py ‐‐‐》管道文件,里面只有一個(gè)類,用于處理下載數(shù)據(jù)的后續(xù)處理
默認(rèn)是300優(yōu)先級(jí),值越小優(yōu)先級(jí)越高(1‐1000)
settings.py ‐‐‐》配置文件 比如:是否遵守robots協(xié)議,User‐Agent定義等
我們以58同城的網(wǎng)頁(yè)為例,我們創(chuàng)建一個(gè)scrapy文件
6. 創(chuàng)建爬蟲(chóng)文件:
(1)跳轉(zhuǎn)到spiders文件夾 cd 目錄名字/目錄名字/spiders
(2)scrapy genspider 爬蟲(chóng)名字 網(wǎng)頁(yè)的域名
爬蟲(chóng)文件的基本組成:
繼承scrapy.Spider類
name = 'baidu' ‐‐‐》 運(yùn)行爬蟲(chóng)文件時(shí)使用的名字
allowed_domains ‐‐‐》 爬蟲(chóng)允許的域名,在爬取的時(shí)候,如果不是此域名之下的
url,會(huì)被過(guò)濾掉
start_urls ‐‐‐》 聲明了爬蟲(chóng)的起始地址,可以寫(xiě)多個(gè)url,一般是一個(gè)
parse(self, response) ‐‐‐》解析數(shù)據(jù)的回調(diào)函數(shù)
response.text ‐‐‐》響應(yīng)的是字符串
response.body ‐‐‐》響應(yīng)的是二進(jìn)制文件
response.xpath()‐》xpath方法的返回值類型是selector列表
extract() ‐‐‐》提取的是selector對(duì)象的是data
extract_first() ‐‐‐》提取的是selector列表中的第一個(gè)數(shù)據(jù)
import scrapy
class TcSpider(scrapy.Spider):
name = "tc"
allowed_domains = ["hezhou.58.com"]
start_urls = ["https://hezhou.58.com/sou/?key=%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91&classpolicy=classify_B%2Cuuid_BWFczZwN8WKQ2ENkAYcww7TidZFSpKTz&search_uuid=BWFczZwN8WKQ2ENkAYcww7TidZFSpKTz&search_type=input"]
def parse(self, response):
content=response.text
span=response.xpath('//div[@id="filter"]/div[@class="tabs"]/a/span')[0]
print('=======')
print(span.extract())
7.運(yùn)行爬蟲(chóng)文件:
scrapy crawl 爬蟲(chóng)名稱
注意:應(yīng)在spiders文件夾內(nèi)執(zhí)行
scrapy架構(gòu)組成
1.(1)引擎 ‐‐‐》自動(dòng)運(yùn)行,無(wú)需關(guān)注,會(huì)自動(dòng)組織所有的請(qǐng)求對(duì)象,分發(fā)給下載器
(2)下載器 ‐‐‐》從引擎處獲取到請(qǐng)求對(duì)象后,請(qǐng)求數(shù)據(jù)
(3)spiders ‐‐‐》Spider類定義了如何爬取某個(gè)(或某些)網(wǎng)站。包括了爬取的動(dòng)作(例
如:是否跟進(jìn)鏈接)以及如何從網(wǎng)頁(yè)的內(nèi)容中提取結(jié)構(gòu)化數(shù)據(jù)(爬取item)。 換句話說(shuō),Spider就是您定義爬取的動(dòng)作及
分析某個(gè)網(wǎng)頁(yè)(或者是有些網(wǎng)頁(yè))的地方。
(4)調(diào)度器 ‐‐‐》有自己的調(diào)度規(guī)則,無(wú)需關(guān)注
(5)管道(Item pipeline) ‐‐‐》最終處理數(shù)據(jù)的管道,會(huì)預(yù)留接口供我們處理數(shù)據(jù)
當(dāng)Item在Spider中被收集之后,它將會(huì)被傳遞到Item Pipeline,一些組件會(huì)按照一定的順序執(zhí)行對(duì)Item的處理。
每個(gè)item pipeline組件(有時(shí)稱之為“Item Pipeline”)是實(shí)現(xiàn)了簡(jiǎn)單方法的Python類。他們接收到Item并通過(guò)它執(zhí)行
一些行為,同時(shí)也決定此Item是否繼續(xù)通過(guò)pipeline,或是被丟棄而不再進(jìn)行處理。
以下是item pipeline的一些典型應(yīng)用:
1. 清理HTML數(shù)據(jù)
2. 驗(yàn)證爬取的數(shù)據(jù)(檢查item包含某些字段)
3. 查重(并丟棄)
4. 將爬取結(jié)果保存到數(shù)據(jù)庫(kù)
scrapy工作原理
scrapy shell
1.什么是scrapy shell?
Scrapy終端,是一個(gè)交互終端,供您在未啟動(dòng)spider的情況下嘗試及調(diào)試您的爬取代碼。 其本意是用來(lái)測(cè)試提取
數(shù)據(jù)的代碼,不過(guò)您可以將其作為正常的Python終端,在上面測(cè)試任何的Python代碼。
該終端是用來(lái)測(cè)試XPath或CSS表達(dá)式,查看他們的工作方式及從爬取的網(wǎng)頁(yè)中提取的數(shù)據(jù)。 在編寫(xiě)您的spider時(shí),該
終端提供了交互性測(cè)試您的表達(dá)式代碼的功能,免去了每次修改后運(yùn)行spider的麻煩。
一旦熟悉了Scrapy終端后,您會(huì)發(fā)現(xiàn)其在開(kāi)發(fā)和調(diào)試spider時(shí)發(fā)揮的巨大作用。
2.安裝ipython
安裝:pip install ipython
簡(jiǎn)介:如果您安裝了 IPython ,Scrapy終端將使用 IPython (替代標(biāo)準(zhǔn)Python終端)。 IPython 終端與其他相
比更為強(qiáng)大,提供智能的自動(dòng)補(bǔ)全,高亮輸出,及其他特性。
3.應(yīng)用:(1)scrapy shell www.baidu.com
(2)scrapy shell http://www.baidu.com
(3) scrapy shell "http://www.baidu.com"
(4) scrapy shell "www.baidu.com"
語(yǔ)法:
(1)response對(duì)象:
response.body
response.text
response.url
response.status
(2)response的解析:
response.xpath() (常用)
使用xpath路徑查詢特定元素,返回一個(gè)selector列表對(duì)象
response.css()
使用css_selector查詢?cè)?,返回一個(gè)selector列表對(duì)象
獲取內(nèi)容 :response.css('#su::text').extract_first()
獲取屬性 :response.css('#su::attr(“value”)').extract_first()
(3)selector對(duì)象(通過(guò)xpath方法調(diào)用返回的是seletor列表)
extract()
提取selector對(duì)象的值
如果提取不到值 那么會(huì)報(bào)錯(cuò)
使用xpath請(qǐng)求到的對(duì)象是一個(gè)selector對(duì)象,需要進(jìn)一步使用extract()方法拆
包,轉(zhuǎn)換為unicode字符串
extract_first()
提取seletor列表中的第一個(gè)值
如果提取不到值 會(huì)返回一個(gè)空值
返回第一個(gè)解析到的值,如果列表為空,此種方法也不會(huì)報(bào)錯(cuò),會(huì)返回一個(gè)空值
xpath()
css()
注意:每一個(gè)selector對(duì)象可以再次的去使用xpath或者css方法
進(jìn)入到scrapy shell的終端 直接在window的終端中輸入scrapy shell 域名如果想看到一些高亮 或者 自動(dòng)補(bǔ)全 那么可以安裝ipython pip install ipython
yield
1. 帶有 yield 的函數(shù)不再是一個(gè)普通函數(shù),而是一個(gè)生成器generator,可用于迭代
2. yield 是一個(gè)類似 return 的關(guān)鍵字,迭代一次遇到y(tǒng)ield時(shí)就返回yield后面(右邊)的值。重點(diǎn)是:下一次迭代
時(shí),從上一次迭代遇到的yield后面的代碼(下一行)開(kāi)始執(zhí)行
3. 簡(jiǎn)要理解:yield就是 return 返回一個(gè)值,并且記住這個(gè)返回的位置,下次迭代就從這個(gè)位置后(下一行)開(kāi)始
案例:
1.當(dāng)當(dāng)網(wǎng) (1)yield(2).管道封裝(3).多條管道下載 (4)多頁(yè)數(shù)據(jù)下載
2.電影天堂 (1)一個(gè)item包含多級(jí)頁(yè)面的數(shù)據(jù)
我們通過(guò)當(dāng)當(dāng)圖書(shū)網(wǎng),爬取了圖書(shū)的圖片,名字和價(jià)格,在爬取圖片時(shí)需要注意的是網(wǎng)站的圖片會(huì)進(jìn)行懶加載,同時(shí)我們爬取的第一個(gè)圖片為none,這時(shí)候我們就需要使用結(jié)構(gòu)控制語(yǔ)句
import scrapy
class DangSpider(scrapy.Spider):
name = "dang"
allowed_domains = ["category.dangdang.com"]
start_urls = ["https://category.dangdang.com/cp01.01.02.00.00.00.html"]
def parse(self, response):
# src=//ul[@id="component_59"]/li/a/img/@src
# alt=//ul[@id="component_59"]/li/a/img/@alt
# price=//ul[@id="component_59"]/li/p[@class="price"]/span[1]/text()
li_list=response.xpath('//ul[@id="component_59"]/li')
for li in li_list:
src = li.xpath('.//img/@data-original').extract_first()
# 第一張圖片和其他的圖片的標(biāo)簽的屬性是不一樣的
# 第一張圖片的src是可以使用的 其他的圖片的地址是data-original
if src:
src = src
else:
src = li.xpath('.//img/@src').extract_first()
name = li.xpath('.//img/@alt').extract_first()
price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()
print(src,name,price)
我們?cè)趇tems.py中定義數(shù)據(jù)結(jié)構(gòu),你需要什么結(jié)構(gòu)就定義什么結(jié)構(gòu)
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class ScrapyDangdang095Item(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 圖片
src=scrapy.Field()
#名字
name=scrapy.Field()
#價(jià)格
price=scrapy.Field()
我們需要使用這個(gè)數(shù)據(jù)結(jié)構(gòu)就需要先導(dǎo)入這個(gè)數(shù)據(jù)結(jié)構(gòu)
#導(dǎo)入
from scrapy_dangdang_095.items import ScrapyDangdang095Item
我們還需要將該數(shù)據(jù)導(dǎo)入數(shù)據(jù)結(jié)構(gòu)中
book=ScrapyDangdang095Item(src=src,name=name,price=price)
我們使用yield進(jìn)行數(shù)據(jù)的下載
1. 帶有 yield 的函數(shù)不再是一個(gè)普通函數(shù),而是一個(gè)生成器generator,可用于迭代
2. yield 是一個(gè)類似 return 的關(guān)鍵字,迭代一次遇到y(tǒng)ield時(shí)就返回yield后面(右邊)的值。重點(diǎn)是:下一次迭代
時(shí),從上一次迭代遇到的yield后面的代碼(下一行)開(kāi)始執(zhí)行
3. 簡(jiǎn)要理解:yield就是 return 返回一個(gè)值,并且記住這個(gè)返回的位置,下次迭代就從這個(gè)位置后(下一行)開(kāi)始
如果想使用管道的話,我們就必須在setting中開(kāi)啟管道 我們?cè)趕etting中將下圖的注釋解開(kāi) 需要注意的是管道可以有很多個(gè),那么管道是有優(yōu)先級(jí)的,優(yōu)先級(jí)的范圍是1到1000 值越小優(yōu)先級(jí)越高 管道代碼
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
# 如果想使用管道的話 那么就必須在settings中開(kāi)啟管道
class ScrapyDangdang095Pipeline:
# 在爬蟲(chóng)文件開(kāi)始的之前就執(zhí)行的一個(gè)方法
def open_spider(self,spider):
self.fp = open('book.json','w',encoding='utf-8')
# item就是yield后面的book對(duì)象
def process_item(self, item, spider):
# 以下這種模式不推薦 因?yàn)槊總鬟f過(guò)來(lái)一個(gè)對(duì)象 那么就打開(kāi)一次文件 對(duì)文件的操作過(guò)于頻繁
# # (1) write方法必須要寫(xiě)一個(gè)字符串 而不能是其他的對(duì)象
# # (2) w模式 會(huì)每一個(gè)對(duì)象都打開(kāi)一次文件 覆蓋之前的內(nèi)容
# with open('book.json','a',encoding='utf-8')as fp:
# fp.write(str(item))
self.fp.write(str(item))
return item
解決對(duì)文件的打開(kāi)和關(guān)閉過(guò)于頻繁
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
# 如果想使用管道的話 那么就必須在settings中開(kāi)啟管道
class ScrapyDangdang095Pipeline:
# 在爬蟲(chóng)文件開(kāi)始的之前就執(zhí)行的一個(gè)方法
def open_spider(self,spider):
self.fp = open('book.json','w',encoding='utf-8')
# item就是yield后面的book對(duì)象
def process_item(self, item, spider):
# 以下這種模式不推薦 因?yàn)槊總鬟f過(guò)來(lái)一個(gè)對(duì)象 那么就打開(kāi)一次文件 對(duì)文件的操作過(guò)于頻繁
# # (1) write方法必須要寫(xiě)一個(gè)字符串 而不能是其他的對(duì)象
# # (2) w模式 會(huì)每一個(gè)對(duì)象都打開(kāi)一次文件 覆蓋之前的內(nèi)容
# with open('book.json','a',encoding='utf-8')as fp:
# fp.write(str(item))
self.fp.write(str(item))
return item
# 在爬蟲(chóng)文件執(zhí)行完之后 執(zhí)行的方法
def close_spider(self,spider):
self.fp.close()
開(kāi)啟多條管道下載
class 自定義:
def process_item(self,item,spider):
return intem
我們自定義為DangDangDownloadPipeline 我們需要在setting中開(kāi)啟管道
'scrapy_dangdang_095.pipelines.DangDangDownloadPipeline':301
我們創(chuàng)建一個(gè)books文件夾用來(lái)接收我們爬取的的圖片 pipelines.py中的代碼如下
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
# 如果想使用管道的話 那么就必須在settings中開(kāi)啟管道
class ScrapyDangdang095Pipeline:
# 在爬蟲(chóng)文件開(kāi)始的之前就執(zhí)行的一個(gè)方法
def open_spider(self,spider):
self.fp = open('book.json','w',encoding='utf-8')
# item就是yield后面的book對(duì)象
def process_item(self, item, spider):
# 以下這種模式不推薦 因?yàn)槊總鬟f過(guò)來(lái)一個(gè)對(duì)象 那么就打開(kāi)一次文件 對(duì)文件的操作過(guò)于頻繁
# # (1) write方法必須要寫(xiě)一個(gè)字符串 而不能是其他的對(duì)象
# # (2) w模式 會(huì)每一個(gè)對(duì)象都打開(kāi)一次文件 覆蓋之前的內(nèi)容
# with open('book.json','a',encoding='utf-8')as fp:
# fp.write(str(item))
self.fp.write(str(item))
return item
# 在爬蟲(chóng)文件執(zhí)行完之后 執(zhí)行的方法
def close_spider(self,spider):
self.fp.close()
import urllib.request
# 多條管道開(kāi)啟
# (1) 定義管道類
# (2) 在settings中開(kāi)啟管道
# 'scrapy_dangdang_095.pipelines.DangDangDownloadPipeline':301
class DangDangDownloadPipeline:
def process_item(self, item, spider):
url = 'http:' + item.get('src')#注意src前面沒(méi)有http,我們需要自行添加
filename = './books/' + item.get('name') + '.jpg'
urllib.request.urlretrieve(url = url, filename= filename)
return item
接下來(lái)哦我們就可以進(jìn)階到多頁(yè)面的下載。 我們獲取每一頁(yè)的請(qǐng)求url尋找規(guī)律
# http://category.dangdang.com/pg3-cp01.01.02.00.00.00.html
# http://category.dangdang.com/pg4-cp01.01.02.00.00.00.html
我們發(fā)現(xiàn)只有在pg 后面的數(shù)字是不同的,我們將其進(jìn)行初始化,將數(shù)字之前的網(wǎng)址和數(shù)字之后的網(wǎng)址進(jìn)行字符串拼接
#初始化
base_url = 'http://category.dangdang.com/pg'
page = 1
if self.page < 100:
self.page = self.page + 1
url = self.base_url + str(self.page) + '-cp01.01.02.00.00.00.html'
# 怎么去調(diào)用parse方法
# scrapy.Request就是scrpay的get請(qǐng)求
# url就是請(qǐng)求地址
# callback是你要執(zhí)行的那個(gè)函數(shù) 注意不需要加()
yield scrapy.Request(url=url,callback=self.parse)
在這段代碼中,回調(diào)函數(shù)是 parse 方法。在 Scrapy 中,回調(diào)函數(shù)指的是在請(qǐng)求完成后執(zhí)行的函數(shù),用于
處理響應(yīng)的數(shù)據(jù)。
在這個(gè)例子中,當(dāng)爬蟲(chóng)發(fā)起請(qǐng)求后,當(dāng)響應(yīng)返回時(shí),Scrapy 將調(diào)用 parse 方法來(lái)處理響應(yīng)的數(shù)據(jù)。
在 yield scrapy.Request(url=url, callback=self.parse) 這行代碼中,callback=self.parse 指定了當(dāng)請(qǐng)求
完成后要執(zhí)行的回調(diào)函數(shù),即 parse 方法。
在 Python 中,self 是一個(gè)慣例,用于引用類實(shí)例中的屬性和方法。在類定義中,self 是第一個(gè)參數(shù),用于指代類的實(shí)例本身。在類的方法內(nèi)部,通過(guò) self 可以訪問(wèn)該類的屬性和方法。
在這個(gè)例子中,self.page 是指該類的一個(gè)屬性,而不是一個(gè)局部變量。通過(guò)在 self 前面加上 self,可以確保在類的其他方法中也可以訪問(wèn)和修改這個(gè)屬性。
如果在方法中直接使用 page,Python 會(huì)認(rèn)為它是一個(gè)局部變量,而不是類的屬性。為了在整個(gè)類中共享和訪問(wèn) page 屬性,需要使用 self.page 來(lái)明確地指示這是類的屬性。
完整代碼如下
import scrapy
from scrapy_dangdang_095.items import ScrapyDangdang095Item
class DangSpider(scrapy.Spider):
name = 'dang'
# 如果是多頁(yè)下載的話 那么必須要調(diào)整的是allowed_domains的范圍 一般情況下只寫(xiě)域名
allowed_domains = ['category.dangdang.com']
start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']
base_url = 'http://category.dangdang.com/pg'
page = 1
def parse(self, response):
# pipelines 下載數(shù)據(jù)
# items 定義數(shù)據(jù)結(jié)構(gòu)的
# src = //ul[@id="component_59"]/li//img/@src
# alt = //ul[@id="component_59"]/li//img/@alt
# price = //ul[@id="component_59"]/li//p[@class="price"]/span[1]/text()
# 所有的seletor的對(duì)象 都可以再次調(diào)用xpath方法
li_list = response.xpath('//ul[@id="component_59"]/li')
for li in li_list:
src = li.xpath('.//img/@data-original').extract_first()
# 第一張圖片和其他的圖片的標(biāo)簽的屬性是不一樣的
# 第一張圖片的src是可以使用的 其他的圖片的地址是data-original
if src:
src = src
else:
src = li.xpath('.//img/@src').extract_first()
name = li.xpath('.//img/@alt').extract_first()
price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()
book = ScrapyDangdang095Item(src=src,name=name,price=price)
# 獲取一個(gè)book就將book交給pipelines
yield book
# 每一頁(yè)的爬取的業(yè)務(wù)邏輯全都是一樣的,所以我們只需要將執(zhí)行的那個(gè)頁(yè)的請(qǐng)求再次調(diào)用parse方法
# 就可以了
# http://category.dangdang.com/pg2-cp01.01.02.00.00.00.html
# http://category.dangdang.com/pg3-cp01.01.02.00.00.00.html
# http://category.dangdang.com/pg4-cp01.01.02.00.00.00.html
if self.page < 100:
self.page = self.page + 1
url = self.base_url + str(self.page) + '-cp01.01.02.00.00.00.html'
# 怎么去調(diào)用parse方法
# scrapy.Request就是scrpay的get請(qǐng)求
# url就是請(qǐng)求地址
# callback是你要執(zhí)行的那個(gè)函數(shù) 注意不需要加()
yield scrapy.Request(url=url,callback=self.parse)
接下來(lái)我們以電影天堂為例 我們獲取網(wǎng)頁(yè)的請(qǐng)求頭網(wǎng)址
我們創(chuàng)建好目錄和爬蟲(chóng)文件
我們先測(cè)試看看網(wǎng)址做了什么反爬 網(wǎng)址并沒(méi)有做反爬 接下來(lái)我們的需求是獲取電影的名字和圖片 我們現(xiàn)在items.py中定義好數(shù)據(jù)結(jié)構(gòu)
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class ScrapyMovie099Item(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
name = scrapy.Field()
src = scrapy.Field()
我們獲取名字和圖片,使用的xpath語(yǔ)句表達(dá),因?yàn)閳D片在鏈接中,則我們使用xpath語(yǔ)句表達(dá)出這個(gè)鏈接
a_list=response.xpath('//div[@class="co_content8"]//td[2]//a[2]')
for a in a_list:
name=a.xpath('./text(').extract_first()
href=a.xpath('./@href').extract_first()
我們要獲取圖片對(duì)第二頁(yè)的鏈接進(jìn)行訪問(wèn),我們自定義一個(gè)第二頁(yè)的鏈接的函數(shù),需要注意的是我們要注意 allowed_domains允許訪問(wèn)的域名的范圍
# 對(duì)第二頁(yè)的鏈接發(fā)起訪問(wèn)
yield scrapy.Request(url=url, callback=self.parse_second, meta={'name': name})
這段代碼使用了 Scrapy 的異步請(qǐng)求機(jī)制,通過(guò) `yield` 關(guān)鍵字創(chuàng)建了一個(gè) `scrapy.Request` 對(duì)象,用于發(fā)起對(duì)第二頁(yè)的請(qǐng)求。
讓我們逐一解釋這段代碼的各個(gè)部分:
- `yield`: 在 Python 中,`yield` 關(guān)鍵字用于生成器函數(shù)中,表示將結(jié)果產(chǎn)生給調(diào)用者,并暫停執(zhí)行當(dāng)前函數(shù)。在 Scrapy 中,使用 `yield` 關(guān)鍵字可以將請(qǐng)求、數(shù)據(jù)等生成為 Scrapy 框架可以處理的對(duì)象,從而實(shí)現(xiàn)異步處理和高效的爬取。
- `scrapy.Request`: 這是 Scrapy 框架中用于發(fā)起 HTTP 請(qǐng)求的類。它接受多個(gè)參數(shù),其中 `url` 參數(shù)是要請(qǐng)求的 URL,`callback` 參數(shù)是指定請(qǐng)求成功后的回調(diào)函數(shù),`meta` 參數(shù)是一個(gè)字典,用于傳遞額外的數(shù)據(jù)。
- `url=url`: 這是請(qǐng)求的 URL,即第二頁(yè)電影信息的鏈接。在原代碼中,它是通過(guò)將第一頁(yè)提取的相對(duì)鏈接拼接而成的絕對(duì)鏈接。
- `callback=self.parse_second`: 這是請(qǐng)求成功后的回調(diào)函數(shù)。在原代碼中,它指定為 `parse_second`,即第二頁(yè)響應(yīng)成功后會(huì)調(diào)用 `parse_second` 方法來(lái)處理響應(yīng)。
- `meta={'name': name}`: 這是一個(gè)字典,用于傳遞額外的數(shù)據(jù)。在原代碼中,它將電影的名稱傳遞給了第二頁(yè)請(qǐng)求,這樣在第二頁(yè)的解析函數(shù)中可以使用這個(gè)名稱來(lái)進(jìn)一步處理電影信息。
總的來(lái)說(shuō),這段代碼的作用是發(fā)起一個(gè)對(duì)第二頁(yè)的異步請(qǐng)求,并在請(qǐng)求成功后調(diào)用 `parse_second` 方法來(lái)處理第二頁(yè)的響應(yīng)。同時(shí),通過(guò) `meta` 參數(shù)將電影名稱傳遞給了第二頁(yè)的解析函數(shù)。
第二個(gè)函數(shù)代碼如下
def parse_second(self, response):
# 注意 如果拿不到數(shù)據(jù)的情況下 一定檢查你的xpath語(yǔ)法是否正確
src = response.xpath('//div[@id="Zoom"]//img/@src').extract_first()
# 接受到請(qǐng)求的那個(gè)meta參數(shù)的值
name = response.meta['name']
movie = ScrapyMovie099Item(src=src, name=name)
yield movie
完整代碼如下
import scrapy
from scrapy_099_mv.items import ScrapyMovie099Item
class MvSpider(scrapy.Spider):
name = "mv"
allowed_domains = ["www.dygod.net"]
start_urls = ["https://www.dygod.net/html/gndy/china/index.html"]
def parse(self, response):
a_list = response.xpath('//div[@class="co_content8"]//td[2]//a[2]')
for a in a_list:
# 獲取第一頁(yè)的name 和 要點(diǎn)擊的鏈接
name = a.xpath('./text()').extract_first()
href = a.xpath('./@href').extract_first()
# 第二頁(yè)的地址是
url = 'https://www.dygod.net/' + href
print(url)
# 對(duì)第二頁(yè)的鏈接發(fā)起訪問(wèn)
yield scrapy.Request(url=url, callback=self.parse_second, meta={'name': name})
def parse_second(self, response):
# 注意 如果拿不到數(shù)據(jù)的情況下 一定檢查你的xpath語(yǔ)法是否正確
src = response.xpath('//div[@id="Zoom"]//img/@src').extract_first()
# 接受到請(qǐng)求的那個(gè)meta參數(shù)的值
name = response.meta['name']
movie = ScrapyMovie099Item(src=src, name=name)#使用from引入的數(shù)據(jù)結(jié)構(gòu)
yield movie#將movie返回給管道,我們需要將管道打開(kāi)
pipelines.py的代碼如下
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
class ScrapyMovie099Pipeline:
def open_spider(self,spider):
self.fp = open('movie.json','w',encoding='utf-8')
def process_item(self, item, spider):
self.fp.write(str(item))
return item
def close_spider(self,spider):
self.fp.close()
這幾個(gè)函數(shù)是定義在 Scrapy 的 Item Pipeline 中的方法,用于對(duì)爬取到的數(shù)據(jù)進(jìn)行處理和存儲(chǔ)。下面是每個(gè)方法的作用:
1. `open_spider(self, spider)`: 這個(gè)方法在爬蟲(chóng)被打開(kāi)時(shí)調(diào)用,用于執(zhí)行一些初始化操作。在這個(gè)例子中,`open_spider` 方法打開(kāi)了一個(gè)名為 `movie.json` 的文件,用于將處理后的數(shù)據(jù)寫(xiě)入到這個(gè)文件中。具體操作是使用 `open` 函數(shù)打開(kāi)一個(gè)文件對(duì)象 `self.fp`,該文件對(duì)象用于寫(xiě)入數(shù)據(jù),并指定編碼格式為 `utf-8`。
2. `process_item(self, item, spider)`: 這個(gè)方法是用來(lái)處理每個(gè)從爬蟲(chóng)中得到的 item 的。在這里,方法將每個(gè) item 轉(zhuǎn)換為字符串形式,并將其寫(xiě)入到之前創(chuàng)建的文件對(duì)象 `self.fp` 中。最后,該方法返回處理后的 item。
3. `close_spider(self, spider)`: 這個(gè)方法在爬蟲(chóng)被關(guān)閉時(shí)調(diào)用,用于執(zhí)行一些清理操作。在這個(gè)例子中,`close_spider` 方法關(guān)閉了之前打開(kāi)的文件對(duì)象 `self.fp`,確保文件處理的完成和資源的釋放。通過(guò)調(diào)用 `close` 方法,將文件對(duì)象 `self.fp` 關(guān)閉,以便文件被正確地保存和釋放資源。
綜合來(lái)看,這幾個(gè)函數(shù)構(gòu)成了一個(gè)簡(jiǎn)單的 Item Pipeline,用于將爬取到的數(shù)據(jù)存儲(chǔ)到名為 `movie.json` 的文件中。具體操作是在 `open_spider` 方法中打開(kāi)文件,然后在 `process_item` 方法中將每個(gè) item 寫(xiě)入文件,最后在 `close_spider` 方法中關(guān)閉文件。這種設(shè)計(jì)模式可以保證數(shù)據(jù)的正確存儲(chǔ)和資源的正確釋放。
Mysql
(1)下載(https://dev.mysql.com/downloads/windows/installer/5.7.html) (2)安裝(https://jingyan.baidu.com/album/d7130635f1c77d13fdf475df.html)
pymysql的使用步驟
1.pip install pymysql
2.pymysql.connect(host,port,user,password,db,charset)
3.conn.cursor()
4.cursor.execute()
CrawlSpider
1.繼承自scrapy.Spider
2.獨(dú)門(mén)秘笈
CrawlSpider可以定義規(guī)則,再解析html內(nèi)容的時(shí)候,可以根據(jù)鏈接規(guī)則提取出指定的鏈接,然后再向這些鏈接發(fā)
送請(qǐng)求
所以,如果有需要跟進(jìn)鏈接的需求,意思就是爬取了網(wǎng)頁(yè)之后,需要提取鏈接再次爬取,使用CrawlSpider是非常
合適的
3.提取鏈接
鏈接提取器,在這里就可以寫(xiě)規(guī)則提取指定鏈接
scrapy.linkextractors.LinkExtractor(
allow = (), # 正則表達(dá)式 提取符合正則的鏈接
deny = (), # (不用)正則表達(dá)式 不提取符合正則的鏈接
allow_domains = (), # (不用)允許的域名
deny_domains = (), # (不用)不允許的域名
restrict_xpaths = (), # xpath,提取符合x(chóng)path規(guī)則的鏈接
restrict_css = () # 提取符合選擇器規(guī)則的鏈接)
4.模擬使用
正則用法:links1 = LinkExtractor(allow=r'list_23_\d+\.html')
xpath用法:links2 = LinkExtractor(restrict_xpaths=r'//div[@class="x"]')
css用法:links3 = LinkExtractor(restrict_css='.x')
5.提取連接
link.extract_links(response)
使用演示
打開(kāi)scrapy shell 網(wǎng)址
提取鏈接提取器可以提取當(dāng)前頁(yè)面中所有符合規(guī)則的鏈接
from scrapy.linkextractors import LinkExtractor
#正則表達(dá)式
# \d:表示數(shù)字 +表示1到多個(gè)數(shù)字
link = LinkExtractor(allow=r'/play/4483-1-\d+\.html')
#輸出
link.extract_linke(response)
#xpath方式
link1 = LinkExtractor(restrict_xpaths="http://div[@class='module-play-list']/div/a/@href")
#輸出
link.extract_linke(response)
6.注意事項(xiàng)
【注1】callback只能寫(xiě)函數(shù)名字符串, callback='parse_item'
【注2】在基本的spider中,如果重新發(fā)送請(qǐng)求,那里的callback寫(xiě)的是 callback=self.parse_item 【注‐
‐稍后看】follow=true 是否跟進(jìn) 就是按照提取連接規(guī)則進(jìn)行提取
柚子快報(bào)邀請(qǐng)碼778899分享:pyhton-8-scrapy
文章鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。