Python爬蟲——Scrapy模塊

Scrapyhtml

Scrapy,Python開發的一個快速、高層次的屏幕抓取和web抓取框架,用於抓取web站點並從頁面中提取結構化的數據。Scrapy用途普遍,能夠用於數據挖掘、監測和自動化測試。
Scrapy吸引人的地方在於它是一個框架,任何人均可以根據需求方便的修改。它也提供了多種類型爬蟲的基類,如BaseSpider、sitemap爬蟲等,最新版本又提供了web2.0爬蟲的支持。
Scrap,是碎片的意思,這個Python的爬蟲框架叫Scrapy。node

Scrapy主要包括瞭如下組件:python

  • 引擎(Scrapy)
    用來處理整個系統的數據流處理, 觸發事務(框架核心)web

  • 調度器(Scheduler)
    用來接受引擎發過來的請求, 壓入隊列中, 並在引擎再次請求的時候返回. 能夠想像成一個URL(抓取網頁的網址或者說是連接)的優先隊列, 由它來決定下一個要抓取的網址是什麼, 同時去除重複的網址正則表達式

  • 下載器(Downloader)
    用於下載網頁內容, 並將網頁內容返回給蜘蛛(Scrapy下載器是創建在twisted這個高效的異步模型上的)數組

  • 爬蟲(Spiders)
    爬蟲是主要幹活的, 用於從特定的網頁中提取本身須要的信息, 即所謂的實體(Item)。用戶也能夠從中提取出連接,讓Scrapy繼續抓取下一個頁面cookie

  • 項目管道(Pipeline)
    負責處理爬蟲從網頁中抽取的實體,主要的功能是持久化實體、驗證明體的有效性、清除不須要的信息。當頁面被爬蟲解析後,將被髮送到項目管道,並通過幾個特定的次序處理數據。併發

  • 下載器中間件(Downloader Middlewares)
    位於Scrapy引擎和下載器之間的框架,主要是處理Scrapy引擎與下載器之間的請求及響應。app

  • 爬蟲中間件(Spider Middlewares)
    介於Scrapy引擎和爬蟲之間的框架,主要工做是處理蜘蛛的響應輸入和請求輸出。框架

  • 調度中間件(Scheduler Middewares)
    介於Scrapy引擎和調度之間的中間件,從Scrapy引擎發送到調度的請求和響應。

Scrapy運行流程以下:

  1. 引擎從調度器中取出一個連接(URL)用於接下來的抓取
  2. 引擎把URL封裝成一個請求(Request)傳給下載器

  3. 下載器把資源下載下來,並封裝成應答包(Response)

  4. 爬蟲解析Response

  5. 解析出實體(Item),則交給實體管道進行進一步的處理

  6. 解析出的是連接(URL),則把URL交給調度器等待抓取

安裝教程

1 Linux 2  pip3 install scrapy 3 Windows 4  a. pip3 install wheel 5       b. 下載twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
6       c. 進入下載目錄,執行 pip3 install Twisted‑17.1.0‑cp35‑cp35m‑win_amd64.whl 7  d. pip3 install scrapy 8       e. 下載並安裝pywin32:https://sourceforge.net/projects/pywin32/files/

新建項目

1 scrapy startproject xxxxx xxxxx爲新建的項目名稱 2 scrapy genspider <name> <domain>
3 例如 4 scrapy genspider chouti chouti.com

操做項目

1 cd進入xxxxx的文件夾 2 
3 scrapy crawl 爬蟲應用名稱

新建Scrapy的目錄內容

 

 1 project_name/
 2  scrapy.cfg  3    project_name/
 4        __init__.py  5  items.py  6  pipelines.py  7  settings.py  8        spiders/
 9            __init__.py 10            project_name.py

 

下面解釋一下文件

  • scrapy.cfg 項目的主配置信息。(真正爬蟲相關的配置信息在settings.py文件中)

  • items.py 設置數據存儲模板,用於結構化數據。

  • pipelines 數據處理行爲,如:通常結構化的數據持久化

  • settings.py 配置文件,如:遞歸的層數、併發數,延遲下載等

  • spiders 爬蟲目錄,如:建立文件,編寫爬蟲規則

選擇器的使用

 

1 from scrapy.selector import Selector, HtmlXPathSelector

選擇器規則

nodeName 選取此節點的全部節點 / 從根節點選取 // 從匹配選擇的當前節點選擇文檔中的節點,不考慮它們的位置 . 選擇當前節點 .. 選取當前節點的父節點 @ 選取屬性 * 匹配任何元素節點 @* 匹配任何屬性節點 Node() 匹配任何類型的節點

具體語法

1 //div[id="Test"]                  #查找id爲Test的標籤
2 //a[re:test(@herf, '/all/hot/\d+')]      # 正則表達式查找a標籤
3 .//h3/text()                             # h3標籤的文本內容
4 .//div[@class='part1']//a[1]/@href       # a標籤的href文本

extract_first() 返回一個字符串

extract()       返回一個數組

攜帶cookies

 

 1 # 方法一
 2 print(response.headers.getlist('Set-Cookie'))  3 # 解析以後的cookie
 4 cookie_dict = {}  5 cookie_jar = CookieJar()  6 cookie_jar.extract_cookies(response, response.request)  7 for k, v in cookie_jar._cookies.items():  8     for i, j in v.items():  9         for m, n in j.items(): 10             self.cookie_dict[m] = n.value 11 print(self.cookie_dict) 12 
13 # 方法二,在Request對象添加meta={'cookiejar': True}
14 yield Request(url=url, callback=self.login, meta={'cookiejar': True})

 

請求頭-可在下載中間件添加

 1 from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware  2 
 3 class MyAgent(UserAgentMiddleware):  4     def __init__(self,user_agent=''):  5         self.user_agent = user_agent  6 
 7     def process_request(self,request,spider):  8         request.headers.setdefault('Host','www.jianshu.com')  9         request.headers.setdefault('User-Agent','Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/53.0.2785.143 Chrome/53.0.2785.143 Safari/537.36') 10 
11 配置文件走一下 12 DOWNLOADER_MIDDLEWARES = { 13     'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware' : None,#必需 ,禁用默認的middleware
14     'Test.middlewares.MyAgent': 543, 15 }

 

去重

1 DUPEFILTER_CLASS = 'scrapy.dupefilter.RFPDupeFilter'
2 DUPEFILTER_DEBUG = False 3 JOBDIR = "保存範文記錄的日誌路徑,如:/root/"  # 最終路徑爲 /root/requests.seen

自定義去重

 1 class RepeatUrl:  2     def __init__(self):  3         self.visited_url = set()  4 
 5  @classmethod  6     def from_settings(cls, settings):  7         """
 8  初始化時,調用  9  :param settings: 10  :return: 11         """
12         return cls() 13 
14     def request_seen(self, request): 15         """
16  檢測當前請求是否已經被訪問過 17  :param request: 18  :return: True表示已經訪問過;False表示未訪問過 19         """
20         if request.url in self.visited_url: 21             return True 22  self.visited_url.add(request.url) 23         return False 24 
25     def open(self): 26         """
27  開始爬去請求時,調用 28  :return: 29         """
30         print('open replication') 31 
32     def close(self, reason): 33         """
34  結束爬蟲爬取時,調用 35  :param reason: 36  :return: 37         """
38         print('close replication') 39 
40     def log(self, request, spider): 41         """
42  記錄日誌 43  :param request: 44  :param spider: 45  :return: 46         """
47         print('repeat', request.url)

 

爬蟲中間件

 1 class SpiderMiddleware(object):  2 
 3     def process_spider_input(self,response, spider):  4         """
 5  下載完成,執行,而後交給parse處理  6  :param response:  7  :param spider:  8  :return:  9         """
10         pass
11 
12     def process_spider_output(self,response, result, spider): 13         """
14  spider處理完成,返回時調用 15  :param response: 16  :param result: 17  :param spider: 18  :return: 必須返回包含 Request 或 Item 對象的可迭代對象(iterable) 19         """
20         return result 21 
22     def process_spider_exception(self,response, exception, spider): 23         """
24  異常調用 25  :param response: 26  :param exception: 27  :param spider: 28  :return: None,繼續交給後續中間件處理異常;含 Response 或 Item 的可迭代對象(iterable),交給調度器或pipeline 29         """
30         return None 31 
32 
33     def process_start_requests(self,start_requests, spider): 34         """
35  爬蟲啓動時調用 36  :param start_requests: 37  :param spider: 38  :return: 包含 Request 對象的可迭代對象 39         """
40         return start_requests
爬蟲中間件
 1 class DownMiddleware1(object):  2     def process_request(self, request, spider):  3         """
 4  請求須要被下載時,通過全部下載器中間件的process_request調用  5  :param request:  6  :param spider:  7  :return:  8  None,繼續後續中間件去下載;  9  Response對象,中止process_request的執行,開始執行process_response 10  Request對象,中止中間件的執行,將Request從新調度器 11  raise IgnoreRequest異常,中止process_request的執行,開始執行process_exception 12         """
13         pass
14 
15 
16 
17     def process_response(self, request, response, spider): 18         """
19  spider處理完成,返回時調用 20  :param response: 21  :param result: 22  :param spider: 23  :return: 24  Response 對象:轉交給其餘中間件process_response 25  Request 對象:中止中間件,request會被從新調度下載 26  raise IgnoreRequest 異常:調用Request.errback 27         """
28         print('response1') 29         return response 30 
31     def process_exception(self, request, exception, spider): 32         """
33  當下載處理器(download handler)或 process_request() (下載中間件)拋出異常 34  :param response: 35  :param exception: 36  :param spider: 37  :return: 38  None:繼續交給後續中間件處理異常; 39  Response對象:中止後續process_exception方法 40  Request對象:中止中間件,request將會被從新調用下載 41         """
42         return None
下載中間件

設置代理

 1 from scrapy.contrib.downloadermiddleware.httpproxy import HttpProxyMiddleware  2     
 3  方式一:使用默認  4  os.environ  5  {  6             http_proxy:http://root:woshiniba@192.168.11.11:9999/
 7             https_proxy:http://192.168.11.11:9999/
 8  }  9  方式二:使用自定義下載中間件 10     
11     def to_bytes(text, encoding=None, errors='strict'): 12         if isinstance(text, bytes): 13             return text 14         if not isinstance(text, six.string_types): 15             raise TypeError('to_bytes must receive a unicode, str or bytes '
16                             'object, got %s' % type(text).__name__) 17         if encoding is None: 18             encoding = 'utf-8'
19         return text.encode(encoding, errors) 20         
21     class ProxyMiddleware(object): 22         def process_request(self, request, spider): 23             PROXIES = [ 24                 {'ip_port': '111.11.228.75:80', 'user_pass': ''}, 25                 {'ip_port': '120.198.243.22:80', 'user_pass': ''}, 26                 {'ip_port': '111.8.60.9:8123', 'user_pass': ''}, 27                 {'ip_port': '101.71.27.120:80', 'user_pass': ''}, 28                 {'ip_port': '122.96.59.104:80', 'user_pass': ''}, 29                 {'ip_port': '122.224.249.122:8088', 'user_pass': ''}, 30  ] 31             proxy = random.choice(PROXIES) 32             if proxy['user_pass'] is not None: 33                 request.meta['proxy'] = to_bytes("http://%s" % proxy['ip_port']) 34                 encoded_user_pass = base64.encodestring(to_bytes(proxy['user_pass'])) 35                 request.headers['Proxy-Authorization'] = to_bytes('Basic ' + encoded_user_pass) 36                 print "**************ProxyMiddleware have pass************" + proxy['ip_port'] 37             else: 38                 print "**************ProxyMiddleware no pass************" + proxy['ip_port'] 39                 request.meta['proxy'] = to_bytes("http://%s" % proxy['ip_port']) 40 
41 配置文件添加 42 DOWNLOADER_MIDDLEWARES = { 43        'step8_king.middlewares.ProxyMiddleware': 500, 44     }
View Code

設置證書

 1 Https訪問  2  Https訪問時有兩種狀況:  3     1. 要爬取網站使用的可信任證書(默認支持)  4         DOWNLOADER_HTTPCLIENTFACTORY = "scrapy.core.downloader.webclient.ScrapyHTTPClientFactory"
 5         DOWNLOADER_CLIENTCONTEXTFACTORY = "scrapy.core.downloader.contextfactory.ScrapyClientContextFactory"
 6         
 7     2. 要爬取網站使用的自定義證書  8         DOWNLOADER_HTTPCLIENTFACTORY = "scrapy.core.downloader.webclient.ScrapyHTTPClientFactory"
 9         DOWNLOADER_CLIENTCONTEXTFACTORY = "step8_king.https.MySSLFactory"
10         
11         # https.py
12         from scrapy.core.downloader.contextfactory import ScrapyClientContextFactory 13         from twisted.internet.ssl import (optionsForClientTLS, CertificateOptions, PrivateCertificate) 14         
15         class MySSLFactory(ScrapyClientContextFactory): 16             def getCertificateOptions(self): 17                 from OpenSSL import crypto 18                 v1 = crypto.load_privatekey(crypto.FILETYPE_PEM, open('/Users/wupeiqi/client.key.unsecure', mode='r').read()) 19                 v2 = crypto.load_certificate(crypto.FILETYPE_PEM, open('/Users/wupeiqi/client.pem', mode='r').read()) 20                 return CertificateOptions( 21                     privateKey=v1,  # pKey對象
22                     certificate=v2,  # X509對象
23                     verify=False, 24                     method=getattr(self, 'method', getattr(self, '_ssl_method', None)) 25                 )
證書

配置文件詳解

 1 BOT_NAME = 'news'  # 爬蟲的名字 會放在USER_AGENT中攜帶到請求裏
 2 
 3 SPIDER_MODULES = ['news.spiders'] # 爬蟲的路徑
 4 NEWSPIDER_MODULE = 'news.spiders' # 爬蟲的路徑
 5 
 6 # USER_AGENT = 'news (+http://www.yourdomain.com)' # 同http請求的請求頭中User-Agent
 7 USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.3964.2 Safari/537.36'
 8 
 9 ROBOTSTXT_OBEY = True # 是否遵照爬蟲的規則,若是遵照會檢測網站中配置文件中是否容許爬蟲
10 
11 CONCURRENT_REQUESTS = 32 # 請求併發數,默認併發16個請求
12 
13 DOWNLOAD_DELAY = 3  # 下載延遲,表示每一個請求訪問前的阻塞3秒
14 CONCURRENT_REQUESTS_PER_DOMAIN = 16 # 針對每一個域名併發請求數
15 CONCURRENT_REQUESTS_PER_IP = 16     # 針對每一個IP的併發請求數
16 
17 COOKIES_ENABLED = True # 是否爬取cookie, 默認爲True
18 COOKIES_DEBUG = True # 開啓cookie的debug模式,每次訪問都會打印cookie
19 
20 
21 TELNETCONSOLE_ENABLED = False   # 監聽6023端口,能夠遠程查看爬蟲的狀況"telnet 127.0.0.1"
22 
23 DEFAULT_REQUEST_HEADERS = {     # http請求的請求頭
24   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 25   'Accept-Language': 'zh-CN,zh;q=0.8', 26 } 27 
28 SPIDER_MIDDLEWARES = { 29    'news.middlewares.NewsSpiderMiddleware': 543, 30 } 31 
32 EXTENSIONS = {  # 爬蟲的信號註冊到此選項
33    # 'scrapy.extensions.telnet.TelnetConsole': None,
34    'news.extensions.MyExtensions':300
35 } 36 
37 ITEM_PIPELINES = { # 爬蟲的pipline註冊到此選項
38    'news.pipelines.NewsPipeline': 300, 39 } 40 
41 SCHEDULER = 'scrapy.core.scheduler.Scheduler'  # 調度器隊列
42 
43 DEPTH_LIMIT = 1     # 爬蟲爬取深度
44 
45 DEPTH_PRIORITY = 0  # 1:廣度優先,0:深度優先
46 
47 DUPEFILTER_CLASS = 'news.duplicatioe.MyDupeFilter' # url重複過濾器

 我的總結

  • 對於此次scrapy的初步瞭解,更多的去了解scrapy框架的源碼,由於只有源碼纔是一切的起源
  • scrapy是一個分佈式的爬蟲框架,每爬取獲得一個item就直接送到pipeline中進行處理,而不是等全部item都爬取完後再進行處理,這一點要注意。
  • 對於調度器和各類中間件,在setting配置文件要添加
  • Request是一個封裝用戶請求的類,在回調函數中yield該對象表示繼續訪問
  • HtmlXpathSelector用於結構化HTML代碼並提供選擇器功能
  • setting的數字越大,權重越大,先執行
相關文章
相關標籤/搜索