前段時間學習了用Python寫爬蟲,使用Scrapy框架爬取京東的商品信息。商品詳情頁的價格是由js生成的,而通過Scrapy直接爬取的源文件中無價格信息。
通過Selenium、Phantomjs便能實現。下面先介紹Phantomjs。
Phantomjs
作為一個基於webkit內核的沒有UI界面的 瀏覽器 ,大家不必被這個名字嚇到,以為是很復雜的技術,其實只是一個瀏覽器啦。而其中的一些點擊、翻頁等操作則由代碼實現。Phantomjs提供javascript API接口,即我們可以通過js與webkit內核交互。
只需通過Phantomjs test.js的命令就能成功訪問頁面,並將js生成后的內容下載下來。
// a phantomjs example
// test.js varpage =require('webpage').create();//獲取操作dom或web網頁的對象 varfs =require('fs');//獲取文件系統對象,通過它可以操作操作系統的文件操作,包括read、write、move、copy、delete等。 phantom.outputEncoding="utf-8"; //通過page對象打開url鏈接,並可以回調其聲明的回調函數 page.open("http://chaycao.github.io",function(status){ if( status ==="success") { console.log("成功"); fs.write('web.html',page.content,'w'); } else{ console.log("Page failed to load."); } phantom.exit(0); });
關於Phantomjs的詳細介紹可以參照這篇博文: http://blog.csdn.net/tengdazhang770960436/article/details/41320079
Selenium
作為一個用於Web應用程序測試的工具,其測試直接運行在瀏覽器中,框架底層使用JavaScript模擬真實用戶對瀏覽器的操作,從終端用戶的角度測試應用程序。將Selenium與Phantomjs聯系起來,便是我們可以 通過使用Selenium操作Phantomjs 訪問網頁以獲得js生成后的網頁。
在我看來,這里Selenium的作用就像是Scrapy調用Phantomjs的中介。我也存有疑問: “Scrapy是否能直接調用Phantomjs?” 期望回復
Scrapy使用Selenium
需要弄懂一個概念, 下載中間件 ,可以閱讀下官方文檔 http://scrapy-chs.readthedocs.io/zh_CN/1.0/topics/downloader-middleware.html
在settings.py加入
DOWNLOADER_MIDDLEWARES = {
'jdSpider.middlewares.middleware.JavaScriptMiddleware':543,#鍵為中間件類的路徑,值為中間件的順序 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware':None,#禁止內置的中間件 }
第一行為中間件的位置,需要與自己目錄對應,我的目錄是這樣的:

如果運行遇到robots.txt的問題,需要將settings.py中的
ROBOTSTXT_OBEY = False
下面貼上,自定義中間件的代碼:
fromseleniumimportwebdriver
fromscrapy.httpimportHtmlResponse
importtime
classJavaScriptMiddleware(object):
defprocess_request(self, request, spider):
ifspider.name =="jd":
print"PhantomJS is starting..." driver = webdriver.PhantomJS() #指定使用的瀏覽器 # driver = webdriver.Firefox() driver.get(request.url) time.sleep(1) js = "var q=document.documentElement.scrollTop=10000" driver.execute_script(js) #可執行js,模仿用戶操作。此處為將頁面拉至最底端。 time.sleep(3) body = driver.page_source print("訪問"+request.url) returnHtmlResponse(driver.current_url, body=body, encoding='utf-8', request=request) else: return
在spiders/jd.py中parse()方法接收到的response則是我們自定義中間件返回的結果。我們得到的便是js生成后的界面。
# -*- coding: utf-8 -*-
importscrapy classJdSpider(scrapy.Spider): name = "jd" allowed_domains = ["jd.com"] start_urls = ( 'http://search.jd.com/Search?keyword=三星s7&enc=utf-8&wq=三星s7&pvid=tj0sfuri.v70avo', ) defparse(self, response): printresponse.body