整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          小白學 Python(爬蟲框架 Scrapy 入門基

          小白學 Python(爬蟲框架 Scrapy 入門基礎) Selector 選擇器

          我們之前有介紹過通過 pyquery 、 Beautiful Soup 、 lxml 來提取網頁數據。

          但是在 Scrapy 中,同樣也提供了自己獨有的數據提取方式,即 Selector(選擇器)。Selector 是基于 lxml 來構建的,支持 XPath 選擇器、CSS 選擇器以及正則表達式,功能全面,解析速度和準確度非常高。

          獨立使用

          Scrapy Selectors 是 Parsel 庫的包裝。包裝的目的是提供與 Scrapy Response 對象的更好的集成。

          Parsel 是一個獨立的 Web 抓取庫,無需 Scrapy 即可使用。它在后臺使用 lxml 庫,并在 lxml API 之上實現了一個簡單的 API 。這意味著 Scrapy 選擇器的速度和解析精度與 lxml 非常相似。

          我們可以寫一個簡單的示例代碼來測試一下 Selectors 的單獨使用。

          from?scrapy?import?Selector
          
          body?=?'<html><head><title>Hello?Python</title></head></html>'selector?=?Selector(text=body)
          title?=?selector.xpath('//title/text()').extract_first()print(title)

          執行結果如下:

          Hello?Python

          這個簡單的示例我們并沒有在 Scrapy 框架中執行,而是把 Scrapy 中的 Selector 單獨拿出來使用了。

          Selector 的使用同其他解析庫類似,如果方便的話,我們也可以在其他項目中直接使用 Selector 來提取數據。

          Scrapy Shell

          由于 Selector 主要是與 Scrapy 結合使用,如 Scrapy 的回調函數中的參數 response 直接調用 xpath() 或者 css() 方法來提取數據,所以在這里我們借助 Scrapy shell 來模擬 Scrapy 請求的過程,來講解相關的提取方法。

          這里我們借助官方文檔的示例進行演示。

          https://docs.scrapy.org/en/latest/_static/selectors-sample1.html

          為了完整起見,以下是其完整的HTML代碼:

          <html>
          ?<head>
          ??<base??/>
          ??<title>Example?website</title>
          ?</head>
          ?<body>
          ??<div?id='images'>
          ???<a?href='image1.html'>Name:?My?image?1?<br?/><img?src='image1_thumb.jpg'?/></a>
          ???<a?href='image2.html'>Name:?My?image?2?<br?/><img?src='image2_thumb.jpg'?/></a>
          ???<a?href='image3.html'>Name:?My?image?3?<br?/><img?src='image3_thumb.jpg'?/></a>
          ???<a?href='image4.html'>Name:?My?image?4?<br?/><img?src='image4_thumb.jpg'?/></a>
          ???<a?href='image5.html'>Name:?My?image?5?<br?/><img?src='image5_thumb.jpg'?/></a>
          ??</div>
          ?</body></html>

          首先,讓我們開啟 Scrapy shell,在命令行輸入如下命令:

          scrapy?shell?https://docs.scrapy.org/en/latest/_static/selectors-sample1.html

          這時,我們進入了 Scrapy Shell 模式,其實就是 Scrapy 發起了一次請求,然后把一些可操作的變量傳遞給我們:

          Xpath 選擇器

          目前我們在 Scrapy shell 之中,這里我們主要操作的對象是 response 。

          response 有一個屬性是 selector ,我們可以通過調用 response.selector.xpath 對數據進行獲取,同時, Scrapy 為我們提供了兩個更加簡潔的方法, response.xpath() 和 response.css() ,這兩個方法完全等同于 response.selector.xpath() 和 response.selector.css() 。

          出于寫法上的簡便考慮,小編后續的代碼將全部使用 response.xpath() 和 response.css() 。

          首先,我們簡單的獲取一下 a 標簽:

          >>>?result?=?response.xpath('//a')>>>?result
          [<Selector?xpath='//a'?data='<a?href="image1.html">Name:?My?image?...'>,?<Selector?xpath='//a'?data='<a?href="image2.html">Name:?My?image?...'>,?<Selector?xpath='//a'?data='<a?href="image3.html">Name:?My?image?...'>,?<Selector?xpath='//a'?data='<a?href="image4.html">Name:?My?image?...'>,?<Selector?xpath='//a'?data='<a?href="image5.html">Name:?My?image?...'>]>>>?type(result)
          <class?'scrapy.selector.unified.SelectorList'>

          這里我們獲取到的結果是由 Selector 組成的列表: SelectorList 。

          它的類型是 scrapy.selector.unified.SelectorList

          SelectorList 和 Selector 都可以繼續調用 xpath() 和 css() 等方法來進一步提取數據。

          接著上面的例子,我們繼續嘗試獲取 a 標簽中的 img 標簽:

          >>>?result.xpath('./img')
          [<Selector?xpath='./img'?data='<img?src="image1_thumb.jpg">'>,?
          <Selector?xpath='./img'?data='<img?src="image2_thumb.jpg">'>,?
          <Selector?xpath='./img'?data='<img?src="image3_thumb.jpg">'>,?
          <Selector?xpath='./img'?data='<img?src="image4_thumb.jpg">'>,?
          <Selector?xpath='./img'?data='<img?src="image5_thumb.jpg">'>]

          這里我們獲取到了所有的 a 標簽中的 img 標簽。

          注意:選擇器的最前方加 . ,這代表提取元素內部的數據,如果沒有加點,則代表從根節點開始提取。

          此處我們用了 ./img 的提取方式,則代表從 a 節點里進行提取。如果此處我們用 //img ,則還是從 html 節點里進行提取。

          現在我們已經獲得了 Selector 類型的節點 a ,如果我們想要將 a 節點元素提取出來,可以使用 extract() 方法,如下:

          >>>?result.extract()
          ['<a?href="image1.html">Name:?My?image?1?<br><img?src="image1_thumb.jpg"></a>',?'<a?href="image2.html">Name:?My?image?2?<br><img?src="image2_thumb.jpg"></a>',?'<a?href="image3.html">Name:?My?image?3?<br><img?src="image3_thumb.jpg"></a>',?'<a?href="image4.html">Name:?My?image?4?<br><img?src="image4_thumb.jpg"></a>',?'<a?href="image5.html">Name:?My?image?5?<br><img?src="image5_thumb.jpg"></a>']

          這里我們如果想要獲得內容的文本內容,可以使用 /text() ,如果想要獲取 href 屬性的內容可以使用 /@href

          我們來看一個完整的示例:

          >>>?response.xpath('//a[@href="image1.html"]/text()').extract()['Name:?My?image?1?']

          這里我們限制的結果,只查到的一條數據,很多情況下我們都會獲得多條數據,這時如果想獲取第一個元素的內容,可以使用索引的方式,如下:

          >>>?response.xpath('//a/text()').extract()[0]'Name:?My?image?1?'

          這樣其實有一點點的小問題,如果當前我們需要的列表為空,這里直接會產生數組越界的異常。

          Scrapy 為我們提供了另一個方法 extract_first() ,專門用來解決這個問題,上面的示例可以改寫成下面的樣子:

          >>>?response.xpath('//a/text()').extract_first()'Name:?My?image?1?'

          同時我們也可以為 extract_first() 方法設置一個默認值參數,這樣當 XPath 規則提取不到內容時會直接使用默認值。

          >>>?response.xpath('//a[@href="image1"]/text()').extract_first('Default')'Default'

          CSS 選擇器

          我們接著看 CSS 選擇器,還是上面的示例,小編這里就不多 BB 了,直接上示例:

          >>>?response.css('a')[<Selector?xpath='descendant-or-self::a'?data='<a?href="image1.html">Name:?My?image?...'>,?<Selector?xpath='descendant-or-self::a'?data='<a?href="image2.html">Name:?My?image?...'>,?<Selector?xpath='descendant-or-self::a'?data='<a?href="image3.html">Name:?My?image?...'>,?<Selector?xpath='descendant-or-self::a'?data='<a?href="image4.html">Name:?My?image?...'>,?<Selector?xpath='descendant-or-self::a'?data='<a?href="image5.html">Name:?My?image?...'>]

          我們同樣可以進行屬性選擇和嵌套選擇:

          >>>?response.css('a[href="image1.html"]').extract()['<a?href="image1.html">Name:?My?image?1?<br><img?src="image1_thumb.jpg"></a>']>>>?response.css('a[href="image1.html"]?img').extract()['<img?src="image1_thumb.jpg">']

          接下來獲取文本值和屬性值的方法稍有區別:

          >>>?response.css('a[href="image1.html"]::text').extract()['Name:?My?image?1?']>>>?response.css('a[href="image1.html"]?img::attr(src)').extract()['image1_thumb.jpg']

          獲取文本和屬性需要用 ::text::attr() 的寫法。

          當然,我們的 CSS 選擇器和 Xpath 選擇器一樣可以嵌套選擇,一個簡單的小示例感受下:

          >>>?response.xpath('//a').css('img').xpath('@src').extract()
          ['image1_thumb.jpg',?'image2_thumb.jpg',?'image3_thumb.jpg',?'image4_thumb.jpg',?'image5_thumb.jpg']

          Selector 選擇器就先介紹到這里了,轉發此文+關注 并私信小編“資料”即可免費領取2010最新python資料和零基礎入門教程!

          不定期分享干貨,歡迎初學和進階中的小伙伴!

          多數現代網站都使用客戶端 JavaScript 框架,例如 React、Vue 或 Angular。在沒有服務器端渲染的情況下從動態網站抓取數據通常需要執行 JavaScript 代碼。

          我已經抓取了數百個網站,而且我總是使用 Scrapy。Scrapy 是一個流行的 Python 網頁抓取框架。與其他 Python 抓取庫(例如 Beautiful Soup)相比,Scrapy 幫助您根據一些最佳實踐來構建代碼。Scrapy 負責并發、收集統計數據、緩存、處理重試邏輯和許多其他問題。

          在本文中,我比較了使用 Scrapy 執行 JavaScript 的最流行的解決方案,包括如何擴展無頭瀏覽器,并介紹了與 ScrapingBee API 的開源集成以支持 JavaScript 和代理輪換。

          使用 Scrapy 抓取動態網站

          使用 Scrapy 抓取客戶端呈現的網站曾經很痛苦。我經常自己檢查瀏覽器網絡工具上的 API 請求并從 JavaScript 變量中提取數據。雖然這些 hack 可能適用于某些網站,但我發現這些代碼比傳統的 XPATH 更難理解和維護。但要直接從 HTML 中抓取客戶端數據,您首先需要執行 JavaScript 代碼。

          用于無頭瀏覽器的 Scrapy 中間件

          無頭瀏覽器是沒有圖形用戶界面的網絡瀏覽器。我使用了三個庫來使用 Scrapy 執行 JavaScript:scrapy-selenium、scrapy-splash 和 scrapy-scrapingbee。

          所有三個庫都集成為 Scrapy下載器中間件。一旦在您的項目設置中進行配置,您就不會從您的spiders產生一個正常的 Scrapy 請求,而是產生一個 SeleniumRequest、SplashRequest 或 ScrapingBeeRequest。

          使用 Selenium 在 Scrapy 中執行

          在本地,您可以使用帶有scrapy-selenium中間件的 Scrapy 與無頭瀏覽器交互。Selenium 是一個與瀏覽器交互的框架,通常用于測試應用程序、網頁抓取和截屏。

          Selenium 需要一個Web 驅動程序來與瀏覽器交互。例如,Firefox 要求您安裝 geckodriver。然后,您可以在 Scrapy 項目設置中配置 Selenium。

          
          
          from shutil import which
          
          SELENIUM_DRIVER_NAME='firefox'
          
          SELENIUM_DRIVER_EXECUTABLE_PATH=which('geckodriver')
          
          SELENIUM_DRIVER_ARGUMENTS=['-headless']
          
          DOWNLOADER_MIDDLEWARES={
          
              'scrapy_selenium.SeleniumMiddleware': 800
          
          }

          在你的spiders中,你可以產生一個 SeleniumRequest。

          from scrapy_selenium import SeleniumRequest
          
          yield SeleniumRequest(url, callback=self.parse)

          Selenium 允許您使用 Python 和 JavaScript 與瀏覽器進行交互。驅動程序對象可以從 Scrapy 響應中訪問。有時在單擊按鈕后檢查 HTML 代碼會很有用。在本地,您可以使用 ipdb 調試器設置斷點來檢查 HTML 響應。

          def parse(self, response):
          
          
              driver=response.request.meta['driver']
              driver.find_element_by_id('show-price').click()
          
          
              import ipdb; ipdb.set_trace()
              print(driver.page_source)
          

          否則,可以從響應對象訪問 Scrapy XPATH 和 CSS 選擇器以從 HTML 中選擇數據。

          def parse(self, response):
              title=response.selector.xpath(
                  '//title/@text'
              ).extract_first()

          SeleniumRequest 接受一些額外的參數,例如在返回響應之前等待的 wait_time,等待 HTML 元素的 wait_until,截取屏幕截圖的屏幕截圖和用于執行自定義 JavaScript 腳本的腳本。

          在生產中,scrapy-selenium 的主要問題是沒有簡單的方法來設置Selenium 網格以在遠程機器上運行多個瀏覽器實例。接下來,我將比較兩種使用 Scrapy 大規模執行 JavaScript 的解決方案。

          使用 Splash 在 Scrapy 中執行 JavaScript

          Splash是一種帶有 API 的 Web 瀏覽器即服務。它由 Scrapy 的主要貢獻者 Scrapinghub 維護,并通過scrapy-splash中間件與 Scrapy 集成。它也可以由 Scrapinghub 托管。

          Splash 創建于 2013 年,在無頭 Chrome 和其他主要無頭瀏覽器于 2017 年發布之前。從那時起,其他流行的項目(如 PhantomJS)已停止使用,轉而支持 Firefox、Chrome 和 Safari 無頭瀏覽器。

          您可以使用 Docker 在本地運行 Splash 實例。

          docker run -p 8050:8050 scrapinghub/splash`
          

          配置 Splash 中間件需要添加多個中間件并在項目設置中更改 HttpCompressionMiddleware 的默認優先級。

          SPLASH_URL='http://192.168.59.103:8050'
          
          
          DOWNLOADER_MIDDLEWARES={
              'scrapy_splash.SplashCookiesMiddleware': 723,
              'scrapy_splash.SplashMiddleware': 725,
              'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
          }
          
          
          SPIDER_MIDDLEWARES={
              'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
          }
          
          
          DUPEFILTER_CLASS='scrapy_splash.SplashAwareDupeFilter'
          HTTPCACHE_STORAGE='scrapy_splash.SplashAwareFSCacheStorage'
          

          然后你可以產生一個帶有可選參數 wait 和 lua_source 的 SplashRequest。

          from scrapy_splash import SplashRequest
          
          yield SplashRequest(url, callback=self.parse, args={
          	'wait': 0.5,
              'lua_source': script
          })
          

          Splash 是一種流行的解決方案,因為它已經推出了很長時間,但它有兩個主要問題:它使用自定義的無頭瀏覽器,并且需要在 Lua 中編碼才能與網站交互。由于這兩個問題,在我的最后一個抓取項目中,我決定為 ScrapingBee API 創建一個中間件。

          使用 ScrapingBee 在 Scrapy 中執行 JavaScript

          ScrapingBee是一個 Web 抓取 API,可以為您處理無頭瀏覽器和代理。ScrapingBee 使用最新的無頭 Chrome 版本并支持 JavaScript 腳本。

          與其他兩個中間件一樣,您可以簡單地使用 pip 安裝scrapy-scrapingbee中間件。

          pip install scrapy-scrapingbee

          首先,您需要創建一個 ScrapingBee 帳戶以獲取 API 密鑰。然后你可以根據你的項目設置中的 ScrapingBee 計劃添加下載器中間件并設置并發。

          SCRAPINGBEE_API_KEY='REPLACE-WITH-YOUR-API-KEY'
          
          DOWNLOADER_MIDDLEWARES={
              'scrapy_scrapingbee.ScrapingBeeMiddleware': 725,
          }
          
          CONCURRENT_REQUESTS=1

          然后你可以從 ScrapingBeeSpider 繼承你的蜘蛛并產生一個 ScrapingBeeRequest。

          from scrapy_scrapingbee import ScrapingBeeSpider, ScrapingBeeRequest
          
          class HttpbinSpider(ScrapingBeeSpider):
              name='httpbin'
              start_urls=[
                  'https://httpbin.org',
              ]
          
          
              def start_requests(self):
                  for url in self.start_urls:
                      yield ScrapingBeeRequest(url)
          
          
              def parse(self, response):
                  …

          ScrapingBeeRequest 采用可選的 params 參數來執行 js_snippet,在返回響應之前設置自定義等待,或者使用 wait_for 在 HTML 代碼中等待 CSS 或 XPATH 選擇器。

          在某些網站中,當您滾動瀏覽頁面時,HTML 會異步加載。您可以使用下面的 JavaScript 片段滾動到頁面末尾。

          JS_SNIPPET='window.scrollTo(0, document.body.scrollHeight);'
          
          yield ScrapingBeeRequest(url, params={
                     'js_snippet': JS_SNIPPET,
                     # 'wait': 3000,
                     # 'wait_for': '#swagger-ui',
                 })

          ScrapingBee 收集了其他常見的 JavaScript 片段,以便與ScrapingBee 文檔中的網站進行交互。

          在幕后,scraping-scrapingbee 中間件將原始請求轉換為轉發到 ScrapingBee API 的請求,并對 URL 查詢字符串中的每個參數進行編碼。API 端點記錄在您的 Scrapy 日志中,并且 api_key 被 ScrapingBeeSpider 隱藏。

          2020-06-22 12:32:07 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://app.scrapingbee.com/api/v1/?api_key=HIDDEN&url=https://httpbin.org&js_snippet=d2luZG93LnNjcm9sbFRvKDAsIGRvY3VtZW50LmJvZHkuc2Nyb2xsSGVpZ2h0KTs=&wait=3000> (referer: None)

          在您的蜘蛛的解析方法中,中間件將 response.url 解析為傳遞給 ScrapingBeeRequest 的原始 URL。

          def parse(self, response):
              assert response.url=='https://httpbin.org'
          

          使用 ScrapingBee 的另一個優點是您可以使用以下參數訪問不同國家的住宅代理和開箱即用的代理輪換。

          yield ScrapingBeeRequest(url, params={
             'premium_proxy': True,
             'country_code': 'fr',
          })
          

          使用 Scrapy 緩存和并發來更快地抓取

          Scrapy 在底層使用了 Twisted,這是一個異步網絡框架。Twisted 使 Scrapy 快速并且能夠同時抓取多個頁面。但是,要執行 JavaScript 代碼,您需要使用真正的瀏覽器或無頭瀏覽器來解析請求。無頭瀏覽器有兩個挑戰:它們速度較慢且難以擴展。

          在無頭瀏覽器中執行 JavaScript 并等待所有網絡調用每頁可能需要幾秒鐘。抓取多個頁面時,它會使抓取器顯著變慢。希望 Scrapy 提供緩存來加速生產運行的開發和并發請求。

          在本地,在開發爬蟲時,您可以使用 Scrapy 的內置緩存系統。由于響應存儲在計算機上的隱藏文件夾 .scrapy/httpcache 中,它將使后續運行更快。您可以在項目設置中激活 HttpCacheMiddleware:

          HTTPCACHE_ENABLED=True
          

          無頭瀏覽器的另一個問題是它們會為每個請求消耗內存。在生產環境中,您需要一個可以處理多個瀏覽器的環境。要同時發出多個請求,您可以修改項目設置:

          CONCURRENT_REQUESTS=1
          

          使用 ScrapingBee 時,請記住根據您的 ScrapingBee 計劃設置并發。

          結論

          我比較了三個使用 Scrapy 渲染和執行 JavaScript 的 Scrapy 中間件。Selenium 允許您在所有主要的無頭瀏覽器中使用 Python 與 Web 瀏覽器進行交互,但可能難以擴展。Splash 可以使用 Docker 在本地運行或部署到 Scrapinghub,但依賴于自定義瀏覽器實現,您必須在 Lua 中編寫腳本。ScrapingBee 使用最新的 Chrome 無頭瀏覽器,允許您在 JavaScript 中執行自定義腳本,并為最難抓取的網站提供代理輪換。


          scrapy-selenium

          scrapy-splash

          scrapy-scrapingbee

          本地運行

          是的

          是的,使用 Docker

          遠程擴展

          使用Selenium Grid

          使用 Scrapinghub

          使用ScrapingBee

          腳本語言

          JavaScript、Python

          lua

          JavaScript

          瀏覽器支持

          Chrome, Firefox, Edge, Safari

          Splash

          Latest Headless Chrome

          代理輪換

          由另一項服務 Crawlera 提供

          是的,由相同的中間件提供


          主站蜘蛛池模板: 国产电影一区二区| 91一区二区在线观看精品| 国模私拍一区二区三区| 久久影院亚洲一区| 亚洲AV乱码一区二区三区林ゆな| 无码人妻精品一区二区三区久久 | 人妻aⅴ无码一区二区三区| 久久人做人爽一区二区三区| 国精产品一区一区三区有限在线| 国产精品无码一区二区三区免费 | 国产SUV精品一区二区四| 国产免费av一区二区三区| 一区二区三区91| 肉色超薄丝袜脚交一区二区| 精品国产一区AV天美传媒| 国产一区二区三区在线免费| 国产一区二区三区免费| 亚洲AV无码一区二区三区久久精品| 日本一区中文字幕日本一二三区视频 | 日本成人一区二区| 韩国福利影视一区二区三区| 日韩在线观看一区二区三区| 国产色情一区二区三区在线播放 | 福利一区二区三区视频午夜观看| 久久久久久一区国产精品 | 亚洲av无一区二区三区| 中文字幕无码免费久久9一区9| 亚洲一区二区久久| www亚洲精品少妇裸乳一区二区| 亚洲国产日韩在线一区| 精品人体无码一区二区三区| 五月婷婷一区二区| 免费看一区二区三区四区| 日韩一区二区三区射精| 国产一区二区三区91| 一区二区三区美女视频| 伊人无码精品久久一区二区| 亚洲色无码一区二区三区| 日本一区二区三区在线视频观看免费| 国产在线一区二区三区| 成人在线一区二区|