Scrapy的基础知识
一、Scrapy的作用
Scrapy應該算是Python宇宙中最常用的爬蟲框架了,他是一個較完善的爬蟲框架,同時也是一個比較難學的框架。Scrapy多應用于中型網站內容爬取。
Scrapy的優點:
- 提供內置的HTTP緩存,加速本地開發
- 自動節流調整機制,遵守 robots.txt 的設置
- 自定義爬取深度
- 執行HTTP基本認證,不需要明確保存狀態
- 自動填寫表單
- 自動設置請求中的引用頭
- 支持通過3xx響應重定向,也可以通過HTML元刷新
- 避免被網站使用的 < noscript > meta 重新向困住,以檢查沒有JS支持的頁面
- 默認使用CSS選擇器或XPath編寫解析器
- 可以用過splash或任何其他技術呈現JavaScript頁面
- 有強大的社區支持
- 提供通用spider抓取常見格式
二、Scrapy框架認識
框架認識就不重復介紹,大致是這樣,點這里。
- Scrapy Engine(引擎):負責控制數據流。
- Scheduler(調度器):接收爬取請求(Request)。
- Downloader(下載器):獲取頁面數據,返回response。
- Spider(蜘蛛):分析response,提取信息,返回Item類。
- Item Pipeline(數據管道):處理Item類,數據信息清洗。
- Downloader middlewares(下載器中間件):下載器和引擎中間的特定鉤子,處理下載器傳送給引擎的response,拓展scrapy功能。
- Spider middlewares(Spider中間件):spider和引擎中間特定的鉤子,處理輸入spider的response和spider輸出的item。使得scrapy的功能得到拓展。
三、Scrapy基本認識
1.文件目錄結構
|——(工程名文件)
| |——— _init_.py '''包定義 '''
| |——— items.py '''模型定義 '''
| |——— pipelines.py '''管道定義 '''
| |——— settings.py '''配置文件 '''
| |——— spiders '''蜘蛛(spider)文件夾 '''
| |——— _init_.py '''控制文件'''
|——scrapy.cfg '''運行配置文件 '''
1.1、創建項目
scrapy startproject + ProjectName
運行該命令后即在當前目錄下創建一個Scarpy工程,同時建立工程文件,文件結構如上所訴。這也是官方所推薦的scrapy最小運行框架。
1.2、創建spider
scrapy genspider + SpiderName + Start_Url
Spider 是 Scrapy 中很是重要也很是常見的一個功能,當我們創建一個scrapy項目是,一般都會先編寫spider的邏輯。spider的作用是分析有scrapy引擎返回的爬網內容(即:Response),并決定是否繼續生成新的請求(即:Request),最終返回Item。
1.3、啟動爬網
scrapy crawl + SpiderName
2.數據模型Item
Item可以理解為一種數據容器,作為spider和pipeline的數據載體。spider對Response進行分析,提取具體的數據結構,并生成對應的item,然后有scrapy引擎傳遞給對應的pipeline進行處理。spider只有產生Item,才能進入下一環節,所以使用scrapy必須要先定義Item。
# -*- coding: utf-8 -*-# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.htmlimport scrapyclass ChinanewsSrawlerItem(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()''''我們嘗試定義一個簡單的item'''title = scrapy.Field()price = scrapy.Field()stock = scrapy.Field()date = scrapy.Field()data = scrapy.Field()#Field對象指明了每個字段的元數據(metadata),Field對象接受的值沒有任何限制
3.蜘蛛——spider
spider類定義了如何爬取某些網站,包括爬取的動作以及如何從網頁的內容中提取結構化數據(Item)
# -*- coding: utf-8 -*-
import scrapy
from bs4 import BeautifulSoup
from ..items import ChinanewsSrawlerItemclass ChinanewsSpider(scrapy.Spider):name = 'chinanews'allowed_domains = ['https://?????.com/']start_urls = ['https://www.?????.com/']def parse(self, response):rss = BeautifulSoup(response.body,'html.parser')for item in rss.findAll('item'):fee_item = ChinanewsSrawlerItem()fee_item['title'] = item.titlefee_item['price'] = item.pricefee_item['stock'] = item.stockfee_item['date'] = item.datefee_item['data'] = item.datayield fee_item''' yield關鍵字的作用,有點類似return,都是用于結果的返回。與return不同的是,yield返回的是一個迭代器。yield不會像return直接將當前執行的代碼中斷并返回,而是將當前可被返回的對象生成一個迭代器,\然后繼續執行下一行代碼'''
蜘蛛要從spider 基類中繼承,當然也可以從其他 spider 的其他類繼承。scrapy工具所創建的蜘蛛類有三個屬性。
- name : 蜘蛛的名稱,用于識別。當一個項目中存在多個蜘蛛(spider)時,這個名稱標識就尤為重要。
- allowed_domains :只爬取該域內的內容,自動過濾鏈接到其他域的內容。
- start_urls : 當蜘蛛被啟動時,第一批請求的url。也就是從這個網址開始爬取。
'''
以下用兩個parse函數實現“間接”爬取,用于對比上面的“直接”爬取
'''
# -*- coding: utf-8 -*-
import scrapy
from bs4 import BeautifulSoup
from ..items import ChinanewsSrawlerItemclass ChinanewsSpider(scrapy.Spider):name = 'chinanews'allowed_domains = ['https://?????.com/']start_urls = ['https://www.?????.com/']def parse(self, response):rss = BeautifulSoup(response.body,'html.parser')rss_links = set([item['data'] for i in rss.findAll('a')])for link in rss_links:yield scrapy.Request(url = link , callback = self.parse_feed)def parse_feed(self,response):rss = BeautifulSoup(response.body,'html.parser')for item in rss.findAll('item'):fee_item = ChinanewsSrawlerItem()fee_item['title'] = item.titlefee_item['price'] = item.pricefee_item['stock'] = item.stockfee_item['date'] = item.datefee_item['data'] = item.datayield fee_item
parse是由spider基類中定義的一個空函數,函數體內只有一個pass關鍵字。我們可以將spider理解為一個抽象類,而parse則是所有子類中必須實現的“抽象方法”,因而每個spider中必須有一個能返回item的parse函數,scrapy的調度器會找到parse函數并調用它。
上訴parse函數是并沒有返回fee_item的迭代器,而是返回一個request的迭代器,在request的構造函數中將parse_feed函數引用作為參數輸入。當request對象被下載器發送到目標url并返回之后,就會自動調用parse_feed函數,并將返回的response作為參數傳入,這樣就形成了二次循環。
最后,當parse函數返回的是一個Item的枚舉時,就標志著這個蜘蛛已經完成他需要處理的事情,scrapy引擎將引導工作流進行下一環節,即 “管道” 處理。
4.管道——Pipeline
“管道,”只接收Item并拖過Item執行一些行為,并決定此Item是否繼續通過管道,他只負責輸入和輸出,并且輸入輸出的對象都是Item
# -*- coding: utf-8 -*-# 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.htmlclass ChinanewsSrawlerPipeline(object):def process_item(self, item, spider):return item
每個管道都需要調用 process_item 方法,而且這個方法必須返回一個Item對象或者是拋出一個 DropItem 異常。每個管道每次只能通過一個Item,意味著每次只能處理一個Item對象。
參數:
item :當前處理的Item對象
spider: 產生當前Item對象的spider
4.1、過濾性管道
面對那些沒用的、重復的數據,我們可以通過建立一個過濾性管道來判斷數據的有效性。在 process_item 處理函數中發起 scarapy.exceptions.DropItem 的異常就能完成丟棄動作,從而過濾掉垃圾數據。在此過程中并不用擔心 process_item中發起的異常會使得工程中止。因為管道的每次處理是針對單個Item對象進行的。
'''
建立過濾管道,過濾'tital'中包含'游戲'信息的數據
'''
import scrapy
class BlockPipeline:def process_item(self, item, spider):key = '游戲'if key in item['tital']:raise scrapy.exceptions.DropItemreturn item'''
建立過濾管道,去重
'''
class DoplicatesPipeline:def _int_(self):self.du = set()def process_item(self, item, spider):if self.du in item['tital']:self.du.add(item['tital'])raise scrapy.exceptions.DropItemreturn item
4.2、加工性管道
建立管道,對數據進行加工。
有如,運算求和,加權,格式化等。
4.3、儲存性管道
import jsonclass jsonfeedPipeline(object):def _int_(self):self.json_file = open('feed.json','wt')self.json_file.write('[\n')def process_item(self, item, spider):line = json.dumps(dict(item))+',\n'self.json_file.write(line)return itemdef close_spider(self,spider):self.json_file.write('\n]')self.json_file.close()
如果要將所有的Item保存到一個json文件中,無需手工實現json的儲存。
- 全局性指定:在配置過程中,配置FEED_URI 和FEED_FORMAT 兩個配置項,輸出文件會保存到指定的位置(即:FFED_URI指定的位置)
- 動態指定:在scrapy 命令中加入 -o +文件名稱 ,即可在“根目錄”下生成輸出文件。
4.4、管道引用
管道的引用需要在settings.py文件中進行指定。即指定spider之后使用哪個管道,和使用順序。
如果有兩個不同的item,需要在管道中進行識別,防止出錯。
在setings.py中找到下面的配置內容,該部分內容即指定管道的使用。
ITEM_PIPELINES 內要以全路徑引用,可同時引用多個管道。
管道 “:”后面的數字表示優先級(即:執行順序),數字越小優先級越高,數字的取值范圍0 ~ 1000
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
#ITEM_PIPELINES = {
# 'chinanews_srawler.pipelines.ChinanewsSrawlerPipeline': 300,
#}'''
配置
'''
ITEM_PIPELINES = {'chinanews_srawler.pipelines.BlockPipeline': 300,'chinanews_srawler.pipelines.jsonfeedPipeline': 301,
}
總結
以上是生活随笔為你收集整理的Scrapy的基础知识的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Redis6]常用数据结构_Hash哈
- 下一篇: 什么是对象