- 創建Scrapy項目
1 # https://github.com/My-Sun-Shine/Python/tree/master/Python3/Scrapy_Learn/Scrapy_A 2 scrapy startproject Scrapy_A
- 項目結構:
- scrapy.cfg:Scrapy項目的配置文件,定義了項目文件路徑、不算
- Scrapy_A:項目的模塊,需要從這里引入
- spiders:其中包括一個個Spider的實現,每個Spider都有一個文件
- items.py:定義Item數據結構,存放所有的Item的定義,定義爬取的數據結構
- middlewares.py:定義爬取時的中間件,定義Spider Middlewares和Downloader Middlewares的實現
- pipelines.py:定義數據管道,定義Item Pipeline的實現,存放所有的Item Pipeline的實現
- settings.py:定義項目的全局配置
- 創建爬蟲:進入到Scrapy_A文件中,使用命名行創建一個Spider
1 # 創建quotes.py這個Spider 2 scrapy genspider quotes quotes.toscrape.com 3 # quotes.py 4 # -*- coding: utf-8 -*- 5 import scrapy 6 7 class QuotesSpider(scrapy.Spider): 8 name = 'quotes' # 項目的唯一名字,區分不同的Spider 9 allowed_domains = ['quotes.toscrape.com'] # 允許爬取的域名,如果初始或后續的請求鏈接不是這個域名下的,則請求鏈接會被過濾掉 10 start_urls = ['http://quotes.toscrape.com/'] # 爬蟲啟動時爬取的url列表,初始請求由它來定義 11 12 def parse(self, response): # 該方法負責解析返回的響應、提取數據或者進一步生成要處理的請求 13 """默認情況下,在start_urls里面的鏈接構成的請求完成下載執行后,返回的響應就會作為唯一參數傳給該函數""" 14 pass
- 創建Item:Item是保存爬取數據的容器
1 # items.py 2 import scrapy 3 4 class QuoteItem(scrapy.Item): 5 """創建Item需要繼承scrapy.Item類,定義類型scrapy.Field字段""" 6 text = scrapy.Field() 7 author = scrapy.Field() 8 tags = scrapy.Field()
- 進行爬蟲解析,編寫QuotesSpider
1 # quotes.py 2 import scrapy 3 from Scrapy_A.items import QuoteItem 4 5 class QuotesSpider(scrapy.Spider): 6 name = 'quotes' 7 allowed_domains = ['quotes.toscrape.com'] 8 start_urls = ['http://quotes.toscrape.com/'] 9 10 def parse(self, response): 11 """response是start_urls里面的鏈接爬取后的結果,使用parse()方法進行解析,使用CSS選擇器或者XPath選擇器""" 12 quotes = response.css('.quote') 13 for quote in quotes: 14 item = QuoteItem() # 聲明數據類Item 15 # extract_first()方法獲取第一個元素;extract()方法獲取所有結果組成的列表 16 item['text'] = quote.css('.text::text').extract_first() 17 item['text'] = quote.css('.author::text').extract_first() 18 item['tags'] = quote.css('.tags .tag::text').extract() 19 yield item 20 21 next_page = response.css('.pager .next a::attr("href")').extract_first() # 獲取下一頁 22 url = response.urljoin(next_page) 23 # url:請求鏈接;callback:回調函數,當得到url響應的時候,回調parse()方法 24 yield scrapy.Request(url=url, callback=self.parse)
- 運行爬蟲
1 scrapy crawl quotes # 爬取結果顯示到控制台上 2 scrapy crawl quotes -o quotes.json # 爬取結果保存在JSON文件中 3 scrapy crawl quotes -o quotes.jl # 每一個Item輸出一行JSON,jl是jsonlines的縮寫 4 scrapy crawl quotes -o quotes.jsonlines # 每一個Item輸出一行JSON 5 scrapy crawl quotes -o quotes.csv # 爬取結果保存在CSV文件中 6 scrapy crawl quotes -o quotes.xml # 爬取結果保存在XML文件中 7 scrapy crawl quotes -o quotes.pickle # 爬取結果保存在Pickle文件中 8 scrapy crawl quotes -o quotes.marshal # 爬取結果保存在marshal格式文件中 9 # ftp遠程輸出,需要配置用戶名,密碼,地址,輸出路徑 10 scrapy crawl quotes -o ftp://user:pass@ftp.example.com/path/to/quotes.csv
- 使用Item Pipeline:Item Pipeline為項目管道,當Item生成后,它會自動被傳送到Item Pipeline進行處理(清理HTML數據、驗證爬取數據、檢測爬取字段、查重並丟棄重復內容、將爬取結果保存到數據庫)
1 # pipelines.py 2 # -*- coding: utf-8 -*- 3 from scrapy.exceptions import DropItem 4 import pymongo 5 6 class TextPipeline(object): 7 def __init__(self): 8 self.limit = 50 9 10 def process_item(self, item, spider): 11 """該方法必須返回包含數據的字典或Item對象或者拋出異常;item:每次爬蟲生成的Item對象;spider:爬蟲實例""" 12 if item['text']: 13 if len(item['text']) > self.limit: 14 item['text'] = item['text'][0:self.limit].strip() + '...' 15 return item 16 else: 17 return DropItem("Missing Text") 18 19 class MongoPipeline(object): # 存入數據庫 20 def __init__(self, mongo_uri, mongo_db): 21 self.mongo_uri = mongo_uri # 鏈接 22 self.mongo_db = mongo_db # 數據庫名 23 24 @classmethod # 標識這是一個依賴注入的方式 25 def from_crawler(cls, crawler): 26 """:param crawler: 得到全局配置的每個配置信息來自settings.py""" 27 return cls( 28 mongo_uri=crawler.settings.get('MONGO_URI'), 29 mongo_db=crawler.settings.get('MONGO_DB') 30 ) 31 32 def open_spider(self, spider): # 當爬蟲開啟的時候,這個方法被調用 33 self.client = pymongo.MongoClient(self.mongo_uri) 34 self.db = self.client[self.mongo_db] 35 36 def process_item(self, item, spider): # 實現數據插入 37 name = item.__class__.__name__ 38 self.db[name].insert(dict(item)) 39 return item 40 41 def close_spider(self, spider): # 爬蟲關閉的時候,該方法被調用 42 self.client.close()
- 配置對應Item Pipeline的settings.py
1 # settings.py 2 # 鍵名是Pipeline的類名稱,鍵值是調用優先級,數字越小則對應的Pipeline越先被調用 3 ITEM_PIPELINES = { 4 'Scrapy_A.pipelines.TextPipeline': 300, 5 'Scrapy_A.pipelines.MongoPipeline': 400, 6 } 7 MONGO_URL = 'localhost' 8 MONGO_DB = 'Scrapy_A'
- 再次運行爬蟲
- Spider運行流程:Spider類定義了如何爬取某個網站的流程和解析方式
- 以初始的URL初始化Request,並設置回調函數,當Request成功請求並返回時,Response生成並作為參數傳給該回調函數
- 在回調函數中分析返回的網頁內容,返回的結果有兩種形式:一種是解析到的有效結果返回字典或Item對象,它們可以經過處理或者直接保存;另外一種就是解析得到下一頁的鏈接,可以利用該鏈接構造Request並設置新的回調函數,返回Request等待后續流程
- 如果返回的是字典或Item對象,通過Feed Exports等組件將返回結果存入到文件,如果設置了Pipline的話,可以使用Pipline處理(如過濾、修正)並保存
- 如果返回的是Request,那么Request執行成功得到Response之后,Response會被傳遞給Request中定義的回調函數,在回調函數中可以使用選擇器來分析新得到的網頁內容,並根據分析的數據生成Item