[原創]手把手教你寫網路爬蟲(4):Scrapy入門

来源:https://www.cnblogs.com/tuohai666/archive/2018/04/19/8879765.html
-Advertisement-
Play Games

手把手教你寫網路爬蟲(4) 作者:拓海 摘要:從零開始寫爬蟲,初學者的速成指南! 封面: 上期我們理性的分析了為什麼要學習Scrapy,理由只有一個,那就是免費,一分錢都不用花! 咦?怎麼有人扔西紅柿?好吧,我承認電視看多了。不過今天是沒得看了,為了趕稿,又是一個不眠夜。。。言歸正傳,我們將在這一期 ...


 

手把手教你寫網路爬蟲(4)

作者:拓海

摘要:從零開始寫爬蟲,初學者的速成指南!

封面:

 

 

上期我們理性的分析了為什麼要學習Scrapy,理由只有一個,那就是免費,一分錢都不用花!

 

咦?怎麼有人扔西紅柿?好吧,我承認電視看多了。不過今天是沒得看了,為了趕稿,又是一個不眠夜。。。言歸正傳,我們將在這一期介紹完Scrapy的基礎知識, 如果想深入研究,大家可以參考官方文檔,那可是出了名的全面,我就不占用公眾號的篇幅了。

 

架構簡介

下麵是Scrapy的架構,包括組件以及在系統中發生的數據流的概覽(紅色箭頭所示)。 之後會對每個組件做簡單介紹,數據流也會做一個簡要描述。

 

組件

Engine: 引擎負責控制數據流在系統中所有組件中流動,併在相應動作發生時觸發事件。

Scheduler: 調度器從引擎接受Request並將他們入隊,以便之後引擎請求他們時提供給引擎。

Downloader: 下載器負責獲取頁面數據並提供給引擎,而後提供給Spider。

Spiders: Spider是Scrapy用戶編寫的用於分析Response並提取Item或提取更多需要下載的URL的類。 每個Spider負責處理特定網站。

Item Pipeline: 負責處理被Spider提取出來的Item。典型的功能有清洗、 驗證及持久化操作。

Downloader middlewares: 下載器中間件是在Engine及Downloader之間的特定鉤子(specific hooks),處理Downloader傳遞給Engine的Response。 其提供了一個簡便的機制,通過插入自定義代碼來擴展Scrapy功能。

Spider middlewares: 是在Engine及Spider之間的特定鉤子(specific hook),處理Spider的輸入(Response)和輸出(Items及Requests)。 其提供了一個簡便的機制,通過插入自定義代碼來擴展Scrapy功能。

 

數據流

Scrapy中的數據流由執行引擎控制,其過程如下:

  1. Engine從Spider獲取第一個需要爬取URL(s)。
  2. Engine用Scheduler調度Requests,並向Scheduler請求下一個要爬取的URL。
  3. Scheduler返回下一個要爬取的URL給Engine。
  4. Engine將URL通過Downloader middlewares轉發給Downloader。
  5. 一旦頁面下載完畢,下載器生成一個該頁面的Response,並將其通過Downloader middlewares發送給Engine。
  6. 引擎從Downloader中接收到Response並通過Spider middlewares發送給Spider處理。
  7. Spider處理Response並返回爬取到的Item及新的Request給Engine。
  8. Engine將爬取到的Item給Item Pipeline,然後將Request給Scheduler。
  9. 從第一步開始重覆這個流程,直到Scheduler中沒有更多的URLs。

架構就是這樣,流程和我第二篇里介紹的迷你架構差不多,但擴展性非常強大。

 

One more thing

 

 

Scrapy基於事件驅動網路框架 Twisted 編寫,Twisted是一個非同步非阻塞框架。一說到網路通信框架就會提什麼同步、非同步、阻塞和非阻塞,到底是些啥玩意啊?為啥老是有人暗示或者明示非同步=非阻塞?比如Scrapy文檔里:Scrapy is written with Twisted, a popular event-driven networking framework for Python. Thus, it’s implemented using a non-blocking (aka asynchronous) code for concurrency. 這種說法對嗎?舉個慄子:

出場人物:老張,水壺兩把(普通水壺,簡稱水壺;會響的水壺,簡稱響水壺)

1. 老張把水壺放到火上,立等水開。(同步阻塞)

  老張覺得自己有點傻。

2. 老張把水壺放到火上,去客廳看電視,時不時去廚房看看水開沒有。(同步非阻塞)

  老張還是覺得自己有點傻,於是變高端了,買了把會響笛的那種水壺。水開之後,能大聲發出嘀~~~~的噪音。

3. 老張把響水壺放到火上,立等水開。(非同步阻塞)

  老張覺得這樣傻等意義不大。

4. 老張把響水壺放到火上,去客廳看電視,水壺響之前不再去看它了,響了再去拿壺。(非同步非阻塞)

  老張覺得自己聰明瞭。

所謂同步非同步,只是對於水壺而言。普通水壺,同步;響水壺,非同步。雖然都能幹活,但響水壺可以在自己完工之後,提示老張水開了。這是普通水壺所不能及的。同步只能讓調用者去輪詢自己(情況2中),造成老張效率的低下。

所謂阻塞非阻塞,僅僅對於老張而言。立等的老張,阻塞;看電視的老張,非阻塞。情況1和情況3中老張就是阻塞的,媳婦喊他都不知道。雖然3中響水壺是非同步的,可對於立等的老張沒有太大的意義。所以一般非同步是配合非阻塞使用的,這樣才能發揮非同步的效用。

 

入門教程

 

創建項目

在開始爬取之前,您必須創建一個新的Scrapy項目。 進入您打算存儲代碼的目錄中,運行下列命令:

scrapy startproject tutorial

該命令將會創建包含下列內容的 tutorial 目錄:

tutorial/
    scrapy.cfg            # 項目的配置文件
    tutorial/             # 該項目的python模塊。之後您將在此加入代碼
        __init__.py
        items.py          # 項目中的item文件
        pipelines.py      # 項目中的pipelines文件
        settings.py       # 項目的設置文件
        spiders/          # 放置spider代碼的目錄
            __init__.py

 

 

編寫第一個爬蟲

Spider是用戶編寫用於從單個網站(或者一些網站)爬取數據的類。其包含了一個用於下載的初始URL,以及如何跟進網頁中的鏈接以及如何分析頁面中的內容的方法。

以下為我們的第一個Spider代碼,保存在 tutorial/spiders 目錄下的 quotes_spider.py文件中:

import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"

    def start_requests(self):
        urls = [
            'http://quotes.toscrape.com/page/1/',
            'http://quotes.toscrape.com/page/2/',
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        page = response.url.split("/")[-2]
        filename = 'quotes-%s.html' % page
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log('Saved file %s' % filename)

 

 

為了創建一個Spider,你必須繼承 scrapy.Spider 類, 且定義以下三個屬性:

  1. name: 用於區別Spider。 該名字必須是唯一的,您不可以為不同的Spider設定相同的名字。
  2. start_urls: 包含了Spider在啟動時進行爬取的url列表。 因此,第一個被獲取到的頁面將是其中之一。 後續的URL則從初始的URL獲取到的數據中提取。
  3. parse() 是spider的一個方法。 被調用時,每個初始URL完成下載後生成的Response 對象將會作為唯一的參數傳遞給該函數。 該方法負責解析返回的數據(response data),提取數據以及生成需要進一步處理的URL的 Request 對象。

 

運行我們的爬蟲

進入項目的根目錄,執行下列命令啟動spider:

scrapy crawl quotes

這個命令啟動用於爬取 quotes.toscrape.com 的spider,你將得到類似的輸出:

2017-05-10 20:36:17 [scrapy.core.engine] INFO: Spider opened
2017-05-10 20:36:17 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2017-05-10 20:36:17 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2017-05-10 20:36:17 [scrapy.core.engine] DEBUG: Crawled (404) <GET http://quotes.toscrape.com/robots.txt> (referer: None)
2017-05-10 20:36:17 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/1/> (referer: None)
2017-05-10 20:36:17 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/2/> (referer: None)
2017-05-10 20:36:17 [quotes] DEBUG: Saved file quotes-1.html
2017-05-10 20:36:17 [quotes] DEBUG: Saved file quotes-2.html
2017-05-10 20:36:17 [scrapy.core.engine] INFO: Closing spider (finished)

 

 

提取數據

我們之前只是保存了HTML頁面,並沒有提取數據。現在升級一下代碼,把提取功能加進去。至於如何使用瀏覽器的開發者模式分析網頁,之前已經介紹過了。

import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
        'http://quotes.toscrape.com/page/2/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').extract_first(),
                'author': quote.css('small.author::text').extract_first(),
                'tags': quote.css('div.tags a.tag::text').extract(),
            }

 

 

再次運行這個爬蟲,你將在日誌里看到被提取出的數據:

2017-05-10 20:38:33 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/page/1/>
{'tags': ['life', 'love'], 'author': 'André Gide', 'text': '“It is better to be hated for what you are than to be loved for what you are not.”'}
2017-05-10 20:38:33 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/page/1/>
{'tags': ['edison', 'failure', 'inspirational', 'paraphrased'], 'author': 'Thomas A. Edison', 'text': "“I have not failed. I've just found 10,000 ways that won't work.”"}

 

保存爬取的數據

最簡單存儲爬取的數據的方式是使用 Feed exports:

scrapy crawl quotes -o quotes.json

該命令將採用 JSON 格式對爬取的數據進行序列化,生成quotes.json文件。

在類似本篇教程里這樣小規模的項目中,這種存儲方式已經足夠。如果需要對爬取到的item做更多更為複雜的操作,你可以編寫 Item Pipeline,tutorial/pipelines.py在最開始的時候已經自動創建了。

 

下一步

系列寫到這裡,組裡對下一步的計劃產生了分歧,本人的意思是系列已經接近尾聲了,可領導的意思是,連載可以正式開始了! What? 這不能忍啊!所以我立即做了一個艱難的決定,連載正式開始!詳情下回分解,再見!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近由於項目驗收的事,太忙,沒有來的及更新,我不想草率的寫。我儘量把自己在工作中悟到的工作經驗分享給大家。一定要讓自己有利用價值,否則就沒有競爭力。在公司,你在老闆心中有利用價值,這樣才能加薪。做為程式員最重要的競爭力就是技術過硬,技術過硬靠的是編程思想。 在面向對象中,所有的對象都有宿主。重要的話 ...
  • layout: post title: 2016 08 03 信息系統實踐手記8 兩模塊通訊的一些事 key: 20160803 tags: 對接 卡口 黑名單 佈防 撤防 訂閱 取消 設備 列表 模型 modify_date: 2016 08 03 信息系統實踐手記8 兩模塊通訊的一些事 說明: ...
  • layout: post title: 2016 05 20 信息系統實踐手記7 對接卡口平臺細節 key: 20160520 tags: 對接 卡口 黑名單 佈防 撤防 訂閱 取消 設備 列表 模型 modify_date: 2016 05 20 信息系統實踐手記7 對接卡口平臺細節 說明: 本文 ...
  • 71,談談你對Struts的理解。 1. struts是一個按MVC模式設計的Web層框架,其實它就是一個Servlet,這個Servlet名為ActionServlet,或是ActionServlet的子類。我們可以在web.xml文件中將符合某種特征的所有請求交給這個Servlet處理,這個Se ...
  • 最近區塊鏈技術突然爆火,身邊做技術的朋友茶餘飯後不談點區塊鏈什麼的都被認為是跟不上時代了,為啥會這樣了? 這其實跟比特幣價格去年的突飛猛進是分不開的,比特幣價格從去年初不到一千美金到今年初最高接近兩萬美金,賺錢效應已經足夠博取大家眼球了,吃瓜群眾對比特幣價格一年上漲20倍早已目瞪狗呆,個個備足錢袋, ...
  • 1.安裝Java環境 安裝了Java環境直接下一步,沒有安裝的話:http://www.cnblogs.com/i-tao/p/8587279.html 2.安裝Eclipse開發工具 安裝了Eclipse直接下一步,沒有安裝直接去官網下載Eclipse:https://www.eclipse.or ...
  • 原文地址:http://hadihariri.com/2014/06/24/no-tabs-in-intellij-idea/ I often come across people complaining about some odd behaviour when it comes to edito ...
  • @ResponseBody 在返回的數據不是html標簽的頁面,而是其他某種格式的數據時(如json、xml等)使用; 不在springMvc中配置json的處理的話,我們通常會在Controller層中獲取到數據之後進行類型轉化,將數據轉成json字元串,比如調用fastjson進行轉化,如下 這 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...