Spider
類定義如何爬取指定的一個或多個網站,包括是否要跟進網頁裏的連接和如何提取網頁內容中的數據。php
爬取的過程是相似如下步驟的循環:html
1.經過指定的初始URL初始化Request,並指定回調函數。當Request下載完後,生成Response做爲參數傳給回調函數。初始的Request是經過start_requests()讀取start_urls中的URL來生成的,回調函數爲parse()。 2.在回調函數中分析Response的內容,返回Item對象或者Request或包含兩者的可迭代容器。返回Request對象通過Scrapy處理,下載相應的內容,並調用設置的回調函數。 3.在回調函數中,能夠用選擇器(或者Beautiful Soup,lxml這些解析器)來分析網頁內容,生成Item。 4.生成的Item能夠存入數據庫,或存入到文件。
class scrapy.spiders.Spider:最簡單的爬蟲類。 方法與屬性: name:爬蟲名,要惟一。 allowed_domains:容許爬取的域名列表。 start_urls:初始的URL列表。 custom_settings:參數配置字典,必須是類屬性,由於參數配置在實例化前被更新。 crawler:此屬性是由from_crawler()設置的。 settings:運行此爬蟲的設置。 logger:Python的日誌記錄器,經過爬蟲名建立。 from_crawler(crawler, *args, **kwargs):類方法,用於建立爬蟲。crawler是Crawler的實例對象。 start_requests():當打開爬蟲時調用此方法。會用初始URL列表建立Request。只調用一次。 parse(response):用於處理Response。 log(message[, level, component]):經過封裝logger來發送日誌消息。 closed(reason):爬蟲關閉時調用此方法。
爬蟲能夠接受參數來改變它的行爲。這些參數通常用來定義初始URL,或者限定爬取網站的部份內容,也能夠用來配置其它任何功能。node
在運行crawl
命令時,經過-a
選項來傳遞參數(鍵值對):web
scrapy crawl myspider -a category=electronics
而後能夠在__init__()
初始化函數裏獲取參數,如:正則表達式
class MySpider(scrapy.Spider): name = 'myspider' def __init__(self, category=None, *args, **kwargs): # 直接做爲一個函數參數 super(MySpider, self).__init__(*args, **kwargs) self.start_urls = ['http://www.example.com/categories/%s' % category]
而默認的__init__()
函數會把這些參數定義爲爬蟲的屬性,所以也能夠這樣用:chrome
class MySpider(scrapy.Spider): name = 'myspider' def start_requests(self): yield scrapy.Request('http://www.example.com/categories/%s' % self.category) # 做爲一個屬性
# -*- coding: utf-8 -*- import scrapy from wangyiPro.items import WangyiproItem from selenium import webdriver class WangyiSpider(scrapy.Spider): name = 'wangyi' # allowed_domains = ['www.xxx.com'] start_urls = ['https://news.163.com/'] model_urls = [] #存放五大板塊對應的url def __init__(self): self.bro = webdriver.Chrome(executable_path=r'C:\Users\lucky\Desktop\爬蟲+數據\day07\chromedriver.exe') def parse(self, response): #解析五個板塊對應的頁面鏈接 li_list = response.xpath('//*[@id="index2016_wrap"]/div[1]/div[2]/div[2]/div[2]/div[2]/div/ul/li') indexs = [3,4,6,7,8] for index in indexs: li = li_list[index] #每個板塊的url model_url = li.xpath('./a/@href').extract_first() self.model_urls.append(model_url) #對每個板塊的url發起請求。注意:請求成功後獲取的響應對象中存儲的響應數據是不包含新聞標題數據(動態加載) yield scrapy.Request(url=model_url,callback=self.parse_title) #是用來解析每個板塊頁面中的新聞標題 def parse_title(self,response): #response是不知足需求,由於該response中沒有包含動態加載出來的新聞標題數據 div_list = response.xpath('/html/body/div/div[3]/div[4]/div[1]/div/div/ul/li/div/div') for div in div_list: new_title = div.xpath('.//div[@class="news_title"]/h3/a/text()').extract_first() item = WangyiproItem() item['title'] = new_title detail_url= div.xpath('.//div[@class="news_title"]/h3/a/@href').extract_first() #對新聞詳情頁發起請求,獲取新聞內容 yield scrapy.Request(detail_url,callback=self.parse_detail,meta={'item':item}) #用來解析新聞詳情頁中的新聞內容(不是動態加載) def parse_detail(self,response): content = response.xpath('//*[@id="endText"]//text()').extract() content = ''.join(content) item = response.meta['item'] item['content'] = content yield item #程序所有結束的時候被調用 def closed(self,spider): print('結束爬蟲!!!') self.bro.quit()
建立crawlspider蜘蛛命令:數據庫
scrapy genspider -t crawl yangguang www.xxx.comapp
class scrapy.spiders.CrawlSpider:爬取通常網站的經常使用Spider。定義一些規則來跟進連接的方便機制。 方法和屬性: rules:包含一個或多個Rule對象的列表。如多個Rule匹配了相同連接,第一個被使用。 parse_start_url(response):當start_urls的請求返回時調用此方法。分析最初的返回值並返回Item對象或者Request或包含兩者的可迭代容器。
爬取規則(Rule)dom
class scrapy.spiders.Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None) 參數: link_extractor:LinkExtractor對象,定義瞭如何從頁面提取連接。 callback:可調用對象或字符串,若是是字符串,Spider中同名的函數被調用。從link_extractor中每次獲取到連接時調用。接受的參數爲Repsonse,返回Item對象或者Request或包含兩者的可迭代容器。編寫爬蟲規則時,不要使用parse做爲回調,由於CrawlSpider使用parse來實現邏輯,若是覆蓋了parse,CrawlSpider會運行失敗。 cb_kwargs:傳遞給回調函數的參數字典。 follow:布爾值,從Response提取的連接是否跟進。若是callback爲None,follow默認爲True,不然默認爲False。 process_links:可調用對象或字符串,若是是字符串,Spider中同名的函數被調用。從link_extractor中獲取連接列表時調用,主要用來過濾。 process_request:可調用對象或字符串,若是是字符串,Spider中同名的函數被調用。提取到每一個Request時調用,返回Request或None,用來過濾Request。
CrawlSpider配合Rule的例子:electron
import scrapy from scrapy.spiders import CrawlSpider, Rule from scrapy.linkextractors import LinkExtractor class MySpider(CrawlSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com'] rules = ( # 提取匹配 'category.php',但不匹配'subsection.php'的連接,並跟進連接。 # 沒有callback,意味着follow的默認值爲True Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))), # 提取匹配'item.php'的連接,並用parse_item這個方法來處理 Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'), ) def parse_item(self, response): # TODO item = scrapy.Item() return item
# -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from sunPro.items import SunproItem,SunProDetail # class SunSpider(CrawlSpider): # name = 'sun' # # allowed_domains = ['www.xxx.com'] # start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page='] # #鏈接提取器: # #做用:就是根據指定的規則(allow:正則)進行鏈接的提取 # link = LinkExtractor(allow=r'type=4&page=\d+') # rules = ( # #規則解析器 # #做用:負責對鏈接提取器提取到的鏈接所對應的頁面源碼數據進行指定規則(callback)的解析 # Rule(link, callback='parse_item', follow=True), # #follow=True:將鏈接提取器 繼續 做用到 鏈接提取器提取到的鏈接 所對應的頁面源碼中 # ) # # def parse_item(self, response): # print(response) #深度爬取 class SunSpider(CrawlSpider): name = 'sun' # allowed_domains = ['www.xxx.com'] start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page='] #鏈接提取器: #做用:就是根據指定的規則(allow:正則)進行鏈接的提取 link = LinkExtractor(allow=r'type=4&page=\d+') #使用另外一個鏈接提取期去提取詳情頁的鏈接 link_detail = LinkExtractor(allow=r'question/\d+/\d+\.shtml') rules = ( #規則解析器 #做用:負責對鏈接提取器提取到的鏈接所對應的頁面源碼數據進行指定規則(callback)的解析 Rule(link, callback='parse_item', follow=False), #follow=True:將鏈接提取器 繼續 做用到 鏈接提取器提取到的鏈接 所對應的頁面源碼中 Rule(link_detail,callback='parse_detail') ) def parse_item(self, response): tr_list = response.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr') for tr in tr_list: title = tr.xpath('./td[2]/a[2]/text()').extract_first() num = tr.xpath('./td[1]/text()').extract_first() item = SunproItem() item['title'] = title item['num'] = num yield item def parse_detail(self,response): content = response.xpath('/html/body/div[9]/table[2]//tr[1]/td/div[2]/text()').extract_first() num = response.xpath('/html/body/div[9]/table[1]//tr/td[2]/span[2]/text()').extract_first() num = num.split(':')[-1] item = SunProDetail() item['content'] = content item['num'] = num yield item
class scrapy.spiders.XMLFeedSpider:經過迭代各個節點用於分析XML。迭代器能夠從iternodes,xml和html中選擇。而xml和html要先讀取全部DOM,可能有性能問題,通常推薦使用iternodes。而html則能應對錯誤的XML。 方法和屬性: iterator:選用哪一種迭代器,iternodes(默認),html,或xml。 itertag:開始迭代的節點名。 namespaces:(prefix, uri)形式的元組組成的列表。定義文檔中會被處理的命名空間。register_namespace()被自動調用把prefix和uri生成命名空間。 adapt_response(response):在分析Response前被調用,能夠用來修改內容,返回的也是一個Response。 parse_node(response, selector):當節點符合itertag時被調用。返回Item對象或者Request或包含兩者的可迭代容器。 process_results(response, results):返回結果(Item或Request)時被調用。用於對結果做最後的處理。返回結果的列表(Item或Request)。
class scrapy.spiders.CSVFeedSpider:與XMLFeedSpider類似,只是遍歷的不是節點,而是行。 方法和屬性: delimiter:分隔符,默認爲逗號。 quotechar:每一個字段的特徵,默認爲雙引號。 headers:用來提取字段的行的列表。 parse_row(response, row):row是一個字典,鍵爲提供的或檢測出來的header。能夠覆蓋adapt_response和process_results來進行前處理和後處理。
class scrapy.spiders.SitemapSpider:經過Sitemaps來發現爬取的URL。支持嵌套的sitemap,並能從robots.txt中獲取sitemap的URL。 方法和屬性: sitemap_urls:sitemap的URL列表,也能夠是robots.txt。 sitemap_rules:(regex, callback)形式的元組列表。regex是匹配sitemap提供的URL的正則表達式。callback指定匹配後用於處理的函數。 sitemap_follow:用於匹配要跟進的sitemap的正則表達式的列表。默認狀況全部sitemap都跟進。 sitemap_alternate_links:當一個URL有可選連接時,是否跟進。 sitemap_filter(entries):過濾函數,能夠覆蓋它來基於sitemap入口的屬性來選擇它們。