scrapy爬蟲入門學習筆記(一)
scrapy的安裝很簡單,網上有大量相關的教程,自行搜尋。
1.scrapy架構

- 引擎(scrapy engine)
處理系統的資料流,觸發事件
- 排程器(scheduler)
接受引擎發來的請求,壓入隊列,并在引擎再次請求時傳回。可以想象成一個URL的優先隊列,由它決定下一個抓取的網址是什麼,并進行去重。
- 下載下傳器(downloader)
用于下載下傳網頁内容,并傳回給spider,下載下傳器建立于twisted這個高效的異步模型之上
- 爬蟲(spiders)
從特定網頁爬取自己想要的資訊,即item,送出給引擎
- 管道(pipeline)
處理從網頁中提取的item,對資訊進行存儲、寫等處理
- 下載下傳中間件(downloader middlewares)
處理引擎和下載下傳器之間的請求和響應
- 爬蟲中間件(spider middlewares)
處理spider的響應輸入和請求輸出
- 排程中間件(scheduler middlewares)
對引擎的請求進行排程處理
2.scrapy項目文檔目錄
tree
- scrapy.cfg:項目的配置檔案
- items.py:項目的目标檔案。
- pipelines.py:項目的管道檔案,作用就一個,處理item字段
- settings.py:項目的設定檔案
- spiders:存儲爬蟲代碼目錄
items.py
- 定義結構化的字段,用于儲存爬取到的資料,類似于python中的字典,但提供了額外的保護防止錯誤。
- 建立一個scrapy.Item類,定義類型為scrapy.Field的類屬性來定義一個Item
- 建立一個ITcastItem類,建構Item模型
import scrapy
class ItcastItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
name=scrapy.Field()
# l老師的職稱
title=scrapy.Field()
# 老師資訊
info=scrapy.Field()
# pass
itcast.py
- 爬蟲python檔案
- 定義一個ITcastSpider類,繼承自scrapy.spider
- 需要name、start_urlds和parse
- parse函數中的xpath是xml文檔查找資訊的語言,可用于對xml元素和屬性值進行周遊
class ItcastSpider(scrapy.Spider):
# 爬蟲名,啟動爬蟲時需要的必須參數
name = 'itcast'
# 爬取域範圍,允許爬蟲在這個域名下進行爬取(可選)
# allowed_domains = []
# 起始URL清單,爬蟲執行後第一批請求,将從這個清單中擷取
start_urls = ['http://www.itcast.cn/channel/teacher.shtml']
def parse(self, response):
node_list=response.xpath("//div[@class='li_txt']")
# 存儲所有的items字段
items=[]
for node in node_list:
# 建立item字段,用來存儲資訊
item=ItcastItem()
# xpath對象轉成Unicode字元串,使用extract()
name=node.xpath("./h3/text()").extract()
title=node.xpath("./h4/text()").extract()
info=node.xpath("./p/text()").extract()
item['name']=name[]
item['title']=title[]
item['info']=info[]
items.append(item)
# 傳回給引擎了
return items
yield item//item傳回給pipeline
- yield和return的差別:yield送出但并不傳回,依然繼續執行。return之後函數就結束了。yield隻是在程式執行中送出一個結果。如果所有資料全部儲存在一個清單中,等到程式執行完畢後return,這樣記憶體開銷會很大,而且意外中斷資料就丢失了。
pipelines.py和settings.py
Item 在spider中收集到後,将會傳遞到pipeline,pipeline元件按照響應碼的順序處理item,主要包含以下操作:
- 驗證爬取的資料,比如是否包含某些字段,如name
- 查重并丢棄,URL的查重由排程器完成。資料的查重需要自己做,使用集合set
- 将爬取的結果儲存到檔案或資料庫中。
#pipelines.py
import json
import codecs
class ItcastPipeline(object):
# 第二個是必選的,1和3是可選的,如果需要操作本地磁盤就需要1和3
# 初始化隻執行一次
def __init__(self):
self.f=codecs.open("itcast_pipeline.json",'w',encoding='utf-8')
# 擷取每一個item
def process_item(self, item, spider):
content=json.dumps(dict(item),ensure_ascii=False)+', \n'
self.f.write(content)
# 傳回一個item給引擎,告訴引擎item已經處理好了,可以處理下一個item
# 如果有其他管道檔案,就會交給下一個item
# 也就是說每一個管道類都需要一個returnitem
return item
# 爬蟲關閉也隻執行一次
def close_spider(self,spider):
self.f.close()
# 可以定義處理資料庫的管道檔案,但是需要在setings.py中設定
pipelines.py中的設定需要在settings.py中對應的設定才會生效。
#setings.py
#配置pipeline,每個管道類後跟一個響應碼,依照從小到大優先
ITEM_PIPELINES = {
'ITcast.pipelines.ItcastPipeline': ,
}
3.項目初體驗
項目目的
爬取Tencent招聘資訊,URL:https://hr.tencent.com/position.php?&start=0
建立項目
scrapy startproject tencent
items.py
首先在TencentItem類中定義字段,确定要哪些資訊
class TencentItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
positionName=scrapy.Field()
positiontype=scrapy.Field()
requireNum=scrapy.Field()
positionLocation=scrapy.Field()
positionTime=scrapy.Field()
# pass
建立spider
scrapy genspider Tencent "tencent.com"
寫spider類
# -*- coding: utf-8 -*-
import scrapy
from tencent.items import TencentItem
class TencentSpider(scrapy.Spider):
name = 'Tencent'
allowed_domains = ['tencent.com']
baseurl='https://hr.tencent.com/position.php?&start='
offset=
start_urls=[]
for i in range():
start_urls.append(baseurl+str(offset+*i))
def parse(self, response):
#xpath讀取節點清單
node_list=response.xpath("//tr[@class='even'] | //tr[@class='odd']")
# print(len(node_list))
for node in node_list:
item=TencentItem()
item['positionName']=node.xpath("./td[1]/a/text()").extract()[]
item['positionLink']=node.xpath("./td[1]/a/@href").extract()[]
if len(node.xpath("./td[2]/text()")):
item['positiontype']=node.xpath("./td[2]/text()").extract()[]
item['requireNum']=node.xpath("./td[3]/text()").extract()[]
item['positionLocation']=node.xpath("./td[4]/text()").extract()[]
item['positionTime']=node.xpath("./td[5]/text()").extract()[]
yield item
# if self.offset<3930:
# self.offset+=10
# url=self.baseurl+str(self.offset)
# yield scrapy.Request(url,callback=self.parse)
這裡可以采用多種方法繼續爬取下一頁的資料,可以采用
yield scrapy.Request(url,callback=self.parse)
送出疊代的URL給引擎。也可以把所有的URL一并放到
start_urls
裡面。後一種方法采用并發執行,效率更高。
寫pipeline類
import json
class TencentPipeline(object):
def __init__(self):
self.f=open("tencent.json",'w',encoding='utf-8')
def process_item(self, item, spider):
contents=json.dumps(dict(item),ensure_ascii=False)+',\n'
self.f.write(contents)
return item
def close_spider(self,spider):
self.f.close()
執行
scrapy crawl Tencent