快上車,scrapy爬蟲飆車找福利(二)

上一篇文章實現的最簡單的爬蟲,抓取了某個連接下第一次加載的全部圖片連接。由於存在下拉刷新, 所以怎麼得到該頁面的所有答案是這篇文章須要去處理的事情。css

方案:

  1. 抓包,看下拉刷新向服務器發送什麼請求,模擬去發送請求(結構化數據適用)
  2. selenium執行js的滑動到底部,判斷是否滑動到底部,以此循環。

具體實施;

這裏選擇使用方案2,方案1後面遇到再討論。html

一:selenium的簡單使用。 這裏涉及selenium的安裝,Selenium with Python官方文檔講解的特別簡單。我使用的的chrome(能夠配置無頭屬性)。 注意:須要將下載的driver配置環境變量,以即可以訪問。python

if __name__ == '__main__':
    options = webdriver.ChromeOptions()
    options.add_argument('headless')
    # driver = webdriver.Chrome(options=options)
    driver = webdriver.Chrome()
    driver.implicitly_wait(2)
    driver.get("https://www.zhihu.com/question/22856657")
    time.sleep(2)
    resSoup = BeautifulSoup(driver.page_source, 'lxml')
    items = resSoup.select("figure > span > div")
    print(len(items))
    for item in items:
        print(item)
    #driver.close()
複製代碼

在項目執行代碼能夠看到輸出:python zhihu/spiders/zhihu.py git

image.png
能夠看到共抓到198張圖片,對去 data-src屬性便可得圖片連接。 代碼解釋: 前三行用於啓動一個無頭的driver。若是須要查看加載的狀況,只用第四行代碼便可,執行完畢能夠查看瀏覽器打開的url, 以下。
image.png

接下來三行: 第一行啓動driver的隱式等待,簡單意思就是:2秒內網頁加載完畢就往下執行,不然就加載完2秒,繼續往下執行。 第二行用於打開連接,至關於手動在地址欄輸入連接。 第三行延時,等待網頁加載。 後面的內容前面有接觸。 若是輸出結果和個人相差不大,那麼繼續下一步。github

二:selenium執行js代碼,加載所有內容。web

if __name__ == '__main__':
    options = webdriver.ChromeOptions()
    options.add_argument('headless')
    # driver = webdriver.Chrome(options=options)
    driver = webdriver.Chrome()
    driver.implicitly_wait(2)
    driver.get("https://www.zhihu.com/question/22856657")
    time.sleep(2)

    count = 1
    css_selector = "#root > div > main > div > div.Question-main > div.Question-mainColumn > div > div.Card > button"
    css_selector2 = "#root > div > main > div > div.Question-main > div.Question-mainColumn > div > div.CollapsedAnswers-bar"
    while len(driver.find_elements_by_css_selector(css_selector)) == 0 and \
            len(driver.find_elements_by_css_selector(css_selector2)) == 0:
        print("count:" + str(count))
        js = "var q=document.documentElement.scrollTop=" + str(count * 200000)
        count += 1
        driver.execute_script(js)
        time.sleep(0.5)

    resSoup = BeautifulSoup(driver.page_source, 'lxml')
    items = resSoup.select("figure > span > div")
    print(len(items))
    for item in items:
        print(item)
複製代碼

image.png
結果輸出:共計抓取翻頁13次,抓取662個圖片連接。 中間部分新增的代碼, count用於記錄翻頁次數。 css_selector和css_selector2用於判斷某個元素是否存在,決定是否滑動到底部,以下。
image.png

用一個循環去執行js代碼,簡單意思是滑動到距離頁面頂部x的距離。通過測試,200000/頁是比較好的選擇。chrome

至此,能夠抓取某個連接下的全部圖片。瀏覽器

三: selenium與spider middlewares的結合。 上面一切順利以後, 接下來去使雙方結合。 關於scrapy 的下載中間鍵(DOWNLOADER_MIDDLEWARES): 簡單來講,該中間鍵就是調用process_request, 將獲取url的request通過處理,返回request,response,None三值之一。 返回 request:繼續執行後面的process_request方法(包括中間鍵) response:不知行後面的process_request方法,以此response結果直接返回,執行zhihu/spiders/zhihu.py 的回調方法。 具體請看官方文檔: https://docs.scrapy.org/en/latest/topics/downloader-middleware.html (還有spider middlewares, 本次未用到) bash

image.png

話很少說,開始寫代碼: 在middlewares.py中定義本身的中間鍵:服務器

class PhantomJSMiddleware(object):

    def __init__(self):
        options = webdriver.ChromeOptions()
        options.add_argument('headless')
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(1)

    def process_request(self, request, spider):
        print(request.url)
        driver = self.nextPage(request)
        return HtmlResponse(url=request.url, body=driver.page_source, encoding="utf-8")
        # 翻頁操做

    def nextPage(self, request):
        self.driver.get(request.url)
        time.sleep(2)
        count = 1
        css_selector = "#root > div > main > div > div.Question-main > div.Question-mainColumn > div > div.Card > button"
        css_selector2 = "#root > div > main > div > div.Question-main > div.Question-mainColumn > div > div.CollapsedAnswers-bar"
        # css_selector = "div > a > img"
        # print(len(self.driver.find_elements_by_css_selector(css_selector)))
        while len(self.driver.find_elements_by_css_selector(css_selector)) == 0 and len(
                self.driver.find_elements_by_css_selector(css_selector2)) == 0:
            print("count:" + str(count))
            js = "var q=document.documentElement.scrollTop=" + str(count * 200000)
            count += 1
            self.driver.execute_script(js)
            time.sleep(0.5)
        print(count)
        time.sleep(2)
        return self.driver

    @classmethod
    # 信號的使用
    def from_crawler(cls, crawler):
        print("from_crawler")
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_closed)
        return s

    def spider_opened(self, spider):
        print("spider close")
        self.driver.close()
複製代碼

稍做解釋: __init__函數作初始化工做, nextPage函數根據獲得的request作翻頁操做。 **process_request**函數是中間鍵的必要函數, 啓動中間鍵以後,yield生成器中的request都會通過該函數,而後返回結果(必定要在此函數執行return)。

後面是spiders信號的使用實例, 用於在spiders執行結束的時候作處理工做,好比關閉driver等操做。

setttings.py:配置對下載中間鍵的使用。

DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
    'zhihu.middlewares.PhantomJSMiddleware': 100,
}
複製代碼

以上配置完畢,便可執行爬蟲。 命令行執行 scrapy crawl zhihu啓動爬蟲,注意看日誌,有以下輸出。

image.png

下拉刷新根據網速決定,因此count值會有不一樣。 能夠看到這裏抓取到了660張圖片連接(容許個別偏差)。

至此,對於使用scrapy結合selnium抓取動態網頁已經不是問題。

對於某些須要登陸的連接,打開url以後會直接去到登陸頁。下一篇文章介紹怎麼使用selenium 去登陸,保存cookies, 帶着cookies去請求(多是萬能的登陸方法,對於圖片驗證, 手機驗證碼也可能適用)。

微信:youquwen1226 github:https://github.com/yunshuipiao 歡迎來信一塊兒探討。

相關文章
相關標籤/搜索