小白進階之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到底是個啥?