標籤:

小白進階之Scrapy第五篇(Scrapy-Splash配合CrawlSpider;瞎幾把整的)

估摸著各位小夥伴兒被想使用CrawlSpider的Rule來抓取JS,相當受折磨;

CrawlSpider Rule總是不能和Splash結合。

廢話不多說,手疼····

方法1:

寫一個自定義的函數,使用Rule中的process_request參數;來替換掉Rule本身Request的邏輯。

參考官方文檔:

1、將請求更換為SplashRequest請求:

2、每次請求將本次請求的URL使用Meta參數傳遞下去;

3、重寫 _requests_to_follow 方法:替換響應Response的URL為我們傳遞的URL(否則會格式為Splash的地址)

就像下面這樣

class MySpider(CrawlSpider):nn name = inndann def start_requests(self):n yield SplashRequest(url, dont_process_response=True, args={wait: 0.5}, meta={real_url: url})n n rules = (n Rule(LinkExtractor(allow=(node_d+.htm,)), process_request=splash_request, follow=True),n Rule(LinkExtractor(allow=(content_d+.htm,)), callback="one_parse")n )nn def splash_request(self, request):n """n :param request: Request對象(是一個字典;怎麼取值就不說了吧!!)n :return: SplashRequest的請求n """n # dont_process_response=True 參數表示不更改響應對象類型(默認為:HTMLResponse;更改後為:SplashTextResponse)n # args={wait: 0.5} 表示傳遞等待參數0.5(Splash會渲染0.5s的時間)n # meta 傳遞請求的當前請求的URLn return SplashRequest(url=request.url, dont_process_response=True, args={wait: 0.5}, meta={real_url: request.url})nn def _requests_to_follow(self, response):n """重寫的函數哈!這個函數是Rule的一個方法n :param response: 這貨是啥看名字都知道了吧(這貨也是個字典,然後你懂的d(???*)??)n :return: 追蹤的Requestn """n if not isinstance(response, HtmlResponse):n returnn seen = set()n # 將Response的URL更改為我們傳遞下來的URLn # 需要注意哈! 不能直接直接改!只能通過Response.replace這個魔術方法來改!(當然你改無所謂啦!反正會用報錯來報復你 (`皿′) )並且!!!n # 敲黑板!!!!劃重點!!!!!注意了!!! 這貨只能賦給一個新的對象(你說變數也行,怎麼說都行!(*???)=3)n newresponse = response.replace(url=response.meta.get(real_url))n for n, rule in enumerate(self._rules):n # 我要長一點不然有人看不見------------------------------------newresponse 看見沒!別忘了改!!!n links = [lnk for lnk in rule.link_extractor.extract_links(newresponse)n if lnk not in seen]n if links and rule.process_links:n links = rule.process_links(links)n for link in links:n seen.add(link)n r = self._build_request(n, link)n yield rule.process_request(r)nn def one_parse(self, response):n print(response.url)

class MySpider(CrawlSpider):

name = innda

def start_requests(self):

yield SplashRequest(url, dont_process_response=True, args={wait: 0.5}, meta={real_url: url})

rules = (

Rule(LinkExtractor(allow=(node_d+.htm,)), process_request=splash_request, follow=True),

Rule(LinkExtractor(allow=(content_d+.htm,)), callback="one_parse")

)

def splash_request(self, request):

"""

:param request: Request對象(是一個字典;怎麼取值就不說了吧!!)

:return: SplashRequest的請求

"""

# dont_process_response=True 參數表示不更改響應對象類型(默認為:HTMLResponse;更改後為:SplashTextResponse)

# args={wait: 0.5} 表示傳遞等待參數0.5(Splash會渲染0.5s的時間)

# meta 傳遞請求的當前請求的URL

return SplashRequest(url=request.url, dont_process_response=True, args={wait: 0.5}, meta={real_url: request.url})

def _requests_to_follow(self, response):

"""重寫的函數哈!這個函數是Rule的一個方法

:param response: 這貨是啥看名字都知道了吧(這貨也是個字典,然後你懂的d(???*)??)

:return: 追蹤的Request

"""

if not isinstance(response, HtmlResponse):

return

seen = set()

# 將Response的URL更改為我們傳遞下來的URL

# 需要注意哈! 不能直接直接改!只能通過Response.replace這個魔術方法來改!(當然你改無所謂啦!反正會用報錯來報復你 (`皿′) )並且!!!

# 敲黑板!!!!劃重點!!!!!注意了!!! 這貨只能賦給一個新的對象(你說變數也行,怎麼說都行!(*???)=3)

newresponse = response.replace(url=response.meta.get(real_url))

for n, rule in enumerate(self._rules):

# 我要長一點不然有人看不見------------------------------------newresponse 看見沒!別忘了改!!!

links = [lnk for lnk in rule.link_extractor.extract_links(newresponse)

if lnk not in seen]

if links and rule.process_links:

links = rule.process_links(links)

for link in links:

seen.add(link)

r = self._build_request(n, link)

yield rule.process_request(r)

def one_parse(self, response):

print(response.url)

方法2:

這就很簡單啦!幹掉類型檢查就是了(/≧▽≦)/

就像這樣:

Python

class MySpider(CrawlSpider):nn name = inndann def start_requests(self):n yield SplashRequest(url, args={wait: 0.5})nn rules = (n Rule(LinkExtractor(allow=(node_d+.htm,)), process_request=splash_request, follow=True),n Rule(LinkExtractor(allow=(content_d+.htm,)), callback="one_parse")n )nn def splash_request(self, request):n """n :param request: Request對象(是一個字典;怎麼取值就不說了吧!!)n :return: SplashRequest的請求n """n # dont_process_response=True 參數表示不更改響應對象類型(默認為:HTMLResponse;更改後為:SplashTextResponse)n # args={wait: 0.5} 表示傳遞等待參數0.5(Splash會渲染0.5s的時間)n # meta 傳遞請求的當前請求的URLn return SplashRequest(url=request.url, args={wait: 0.5})nn def _requests_to_follow(self, response):n """重寫的函數哈!這個函數是Rule的一個方法n :param response: 這貨是啥看名字都知道了吧(這貨也是個字典,然後你懂的d(???*)??)n :return: 追蹤的Requestn """n # *************請注意我就是被注釋注釋掉的類型檢查o(TωT)o n # if not isinstance(response, HtmlResponse):n # returnn # ************************************************n seen = set()n # 將Response的URL更改為我們傳遞下來的URLn # 需要注意哈! 不能直接直接改!只能通過Response.replace這個魔術方法來改!並且!!!n # 敲黑板!!!!劃重點!!!!!注意了!!! 這貨只能賦給一個新的對象(你說變數也行,怎麼說都行!(*???)=3)n # newresponse = response.replace(url=response.meta.get(real_url))n for n, rule in enumerate(self._rules):n # 我要長一點不然有人看不見------------------------------------newresponse 看見沒!別忘了改!!!n links = [lnk for lnk in rule.link_extractor.extract_links(response)n if lnk not in seen]n if links and rule.process_links:n links = rule.process_links(links)n for link in links:n seen.add(link)n r = self._build_request(n, link)n yield rule.process_request(r)

class MySpider(CrawlSpider):

name = innda

def start_requests(self):

yield SplashRequest(url, args={wait: 0.5})

rules = (

Rule(LinkExtractor(allow=(node_d+.htm,)), process_request=splash_request, follow=True),

Rule(LinkExtractor(allow=(content_d+.htm,)), callback="one_parse")

)

def splash_request(self, request):

"""

:param request: Request對象(是一個字典;怎麼取值就不說了吧!!)

:return: SplashRequest的請求

"""

# dont_process_response=True 參數表示不更改響應對象類型(默認為:HTMLResponse;更改後為:SplashTextResponse)

# args={wait: 0.5} 表示傳遞等待參數0.5(Splash會渲染0.5s的時間)

# meta 傳遞請求的當前請求的URL

return SplashRequest(url=request.url, args={wait: 0.5})

def _requests_to_follow(self, response):

"""重寫的函數哈!這個函數是Rule的一個方法

:param response: 這貨是啥看名字都知道了吧(這貨也是個字典,然後你懂的d(???*)??)

:return: 追蹤的Request

"""

# *************請注意我就是被注釋注釋掉的類型檢查o(TωT)o

# if not isinstance(response, HtmlResponse):

# return

# ************************************************

seen = set()

# 將Response的URL更改為我們傳遞下來的URL

# 需要注意哈! 不能直接直接改!只能通過Response.replace這個魔術方法來改!並且!!!

# 敲黑板!!!!劃重點!!!!!注意了!!! 這貨只能賦給一個新的對象(你說變數也行,怎麼說都行!(*???)=3)

# newresponse = response.replace(url=response.meta.get(real_url))

for n, rule in enumerate(self._rules):

# 我要長一點不然有人看不見------------------------------------newresponse 看見沒!別忘了改!!!

links = [lnk for lnk in rule.link_extractor.extract_links(response)

if lnk not in seen]

if links and rule.process_links:

links = rule.process_links(links)

for link in links:

seen.add(link)

r = self._build_request(n, link)

yield rule.process_request(r)

以上完畢@_@!!


推薦閱讀:

黃哥說很多人的循環都寫不好, 請看。
用 Python 做文本挖掘的流程
批量看妹子——你的第一個知乎爬蟲(1)
Simpson rule
Python到底是個啥?

TAG:Python | scrapy |