Scrapy框架中分兩類爬蟲,Spider類和CrawlSpider類皮仁。
此案例采用的是CrawlSpider類實現(xiàn)爬蟲魂爪。
它是Spider的派生類,Spider類的設(shè)計原則是只爬取start_url列表中的網(wǎng)頁哩盲,而CrawlSpider類定義了一些規(guī)則(rule)來提供跟進(jìn)link的方便的機(jī)制前方,從爬取的網(wǎng)頁中獲取link并繼續(xù)爬取的工作更適合狈醉。
創(chuàng)建項目指令:
scrapy startproject tencent
模版創(chuàng)建:
scrapy genspider crawl -t tencent 'hr.tencent.com'
CrawlSpider繼承于Spider類,除了繼承過來的屬性外(name惠险、allow_domains)苗傅,還提供了新的屬性和方法:
LinkExtractors
class scrapy.linkextractors.LinkExtractor
Link Extractors 的目的很簡單: 提取鏈接?
每個LinkExtractor有唯一的公共方法是 extract_links(),它接收一個 Response 對象莺匠,并返回一個 scrapy.link.Link 對象金吗。
Link Extractors要實例化一次,并且 extract_links 方法會根據(jù)不同的 response 調(diào)用多次提取鏈接?
主要參數(shù):
allow:滿足括號中“正則表達(dá)式”的值會被提取趣竣,如果為空摇庙,則全部匹配。
deny:與這個正則表達(dá)式(或正則表達(dá)式列表)不匹配的URL一定不提取遥缕。
allow_domains:會被提取的鏈接的domains卫袒。
deny_domains:一定不會被提取鏈接的domains。
restrict_xpaths:使用xpath表達(dá)式单匣,和allow共同作用過濾鏈接夕凝。
rules
在rules中包含一個或多個Rule對象,每個Rule對爬取網(wǎng)站的動作定義了特定操作户秤。如果多個rule匹配了相同的鏈接码秉,則根據(jù)規(guī)則在本集合中被定義的順序,第一個會被使用鸡号。
參數(shù)介紹:
link_extractor:是一個Link Extractor對象转砖,用于定義需要提取的鏈接。
callback: 從link_extractor中每獲取到鏈接時鲸伴,參數(shù)所指定的值作為回調(diào)函數(shù)府蔗,該回調(diào)函數(shù)接受一個response作為其第一個參數(shù)。
注意:當(dāng)編寫爬蟲規(guī)則時汞窗,避免使用parse作為回調(diào)函數(shù)姓赤。由于CrawlSpider使用parse方法來實現(xiàn)其邏輯,如果覆蓋了 parse方法仲吏,crawl spider將會運行失敗不铆。
follow:是一個布爾(boolean)值,指定了根據(jù)該規(guī)則從response提取的鏈接是否需要跟進(jìn)蜘矢。 如果callback為None狂男,follow 默認(rèn)設(shè)置為True ,否則默認(rèn)為False品腹。
process_links:指定該spider中哪個的函數(shù)將會被調(diào)用岖食,從link_extractor中獲取到鏈接列表時將會調(diào)用該函數(shù)。該方法主要用來過濾舞吭。
process_request:指定該spider中哪個的函數(shù)將會被調(diào)用泡垃, 該規(guī)則提取到每個request時都會調(diào)用該函數(shù)析珊。 (用來過濾request)
以下是案例代碼:
item文件
import scrapy
class TencentItem(scrapy.Item):
# 職位
name = scrapy.Field()
# 詳情鏈接
positionlink = scrapy.Field()
#職位類別
positiontype = scrapy.Field()
# 人數(shù)
peoplenum = scrapy.Field()
# 工作地點
worklocation = scrapy.Field()
# 發(fā)布時間
publish = scrapy.Field()
pipeline文件
import json
class TencentPipeline(object):
def __init__(self):
self.filename = open("tencent.json", "w")
def process_item(self, item, spider):
text = json.dumps(dict(item), ensure_ascii = False) + ",\n"
self.filename.write(text.encode("utf-8"))
return item
def close_spider(self, spider):
self.filename.close()
setting文件
BOT_NAME = 'tencent'
SPIDER_MODULES = ['tencent.spiders']
NEWSPIDER_MODULE = 'tencent.spiders'
LOG_FILE = 'tenlog.log'
LOG_LEVEL = 'DEBUG'
LOG_ENCODING = 'utf-8'
ROBOTSTXT_OBEY = True
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
}
ITEM_PIPELINES = {
'tencent.pipelines.TencentPipeline': 300,
}
spider文件
# -*- coding: utf-8 -*-
import scrapy
# 導(dǎo)入鏈接匹配規(guī)則類,用來提取符合規(guī)則的鏈接
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from tencent.items import TencentItem
class TenecntSpider(CrawlSpider):
name = 'tencent1'
# 可選蔑穴,加上會有一個爬去的范圍
allowed_domains = ['hr.tencent.com']
start_urls = ['http://hr.tencent.com/position.php?&start=0#a']
# response中提取 鏈接的匹配規(guī)則忠寻,得出是符合的鏈接
pagelink = LinkExtractor(allow=('start=\d+'))
print (pagelink)
# 可以寫多個rule規(guī)則
rules = [
# follow = True需要跟進(jìn)的時候加上這句。
# 有callback的時候就有follow
# 只要符合匹配規(guī)則存和,在rule中都會發(fā)送請求奕剃,同是調(diào)用回調(diào)函數(shù)處理響應(yīng)
# rule就是批量處理請求
Rule(pagelink, callback='parse_item', follow=True),
]
# 不能寫parse方法,因為源碼中已經(jīng)有了捐腿,回覆蓋導(dǎo)致程序不能跑
def parse_item(self, response):
for each in response.xpath("http://tr[@class='even'] | //tr[@class='odd']"):
# 把數(shù)據(jù)保存在創(chuàng)建的對象中纵朋,用字典的形式
item = TencentItem()
# 職位
# each.xpath('./td[1]/a/text()')返回的是列表,extract轉(zhuǎn)為unicode字符串茄袖,[0]取第一個
item['name'] = each.xpath('./td[1]/a/text()').extract()[0]
# 詳情鏈接
item['positionlink'] = each.xpath('./td[1]/a/@href').extract()[0]
# 職位類別
item['positiontype'] = each.xpath("./td[2]/text()").extract()[0]
# 人數(shù)
item['peoplenum'] = each.xpath('./td[3]/text()').extract()[0]
# 工作地點
item['worklocation'] = each.xpath('./td[4]/text()').extract()[0]
# 發(fā)布時間
item['publish'] = each.xpath('./td[5]/text()').extract()[0]
# 把數(shù)據(jù)交給管道文件
yield item