设置中间件
集成 selenium driver,实现动态加载
以下方法改变了scrapy异步加载,变为了同步加载,会降低运行效率,当然也可以解决,需要重写 downloader(至少要了解 twisted API)
定义中间件
class JSPageMiddleware(object): """通过 chrome 请求动态网页""" def process_request(self, request, spider): """selenium 模拟访问""" # 判断 spider 实例的 name if spider.name == 'jobbole': from scrapy.http import HtmlResponse import time # 请求 URL spider.browser.get(request.url) # 放大窗口 / 严谨一点可使用 try spider.browser.maximize_window() # 避免加载过慢 time.sleep(3) print('request:{0}'.format(request.url)) # 避免重复下载, 直接调用 HtmlResponse 进行返回 # current(当前) browser 请求 url, page_source(页面源) 的 html 页面 # 因为 HtmlResponse 的父类 TextResponse 中 类变量 _DEFAULT_ENCODING 默认为 ascii 码, 根据源页面编码指定编码 return HtmlResponse(url=spider.browser.current_url, body=spider.browser.page_source, encoding='utf-8', request=request)
使用 Spider 构造函数,创建 browser 实例
def __init__(self): chrome_option = webdriver.ChromeOptions() chrome_option.add_argument('blink-settings=imagesEnabled=false') # chrome_option.add_argument('--disable-extensions') # chrome_option.add_experimental_option('debuggerAddress', '127.0.0.1:9222') self.browser = webdriver.Chrome(executable_path='E:/Template/chromedriver.exe', chrome_options=chrome_option) # 使用 super 方法, 防止重复调用 super(JobboleSpider, self).__init__()
信号
Scrapy广泛使用信号来通知某些事件的发生。您可以捕获Scrapy项目中的某些信号(例如,使用扩展名)来执行其他任务,或者扩展Scrapy以添加开箱即用的功能。
即使信号提供了几个参数,捕获它们的处理程序也不需要接受所有参数-信号分配机制将只传递处理程序接收的参数。
您可以通过Signals API连接到信号(或发送自己的 信号)。
优点:可以允许自定义很多逻辑,且不会侵入到Scrapy的代码当中,跟 Django的设计框架是很相像的
def __init__(self):
chrome_option = webdriver.ChromeOptions()
chrome_option.add_argument('blink-settings=imagesEnabled=false')
# chrome_option.add_argument('--disable-extensions')
# chrome_option.add_experimental_option('debuggerAddress', '127.0.0.1:9222')
self.browser = webdriver.Chrome(executable_path='E:/Template/chromedriver.exe', chrome_options=chrome_option)
# 使用 super 方法, 防止重复调用
super(JobboleSpider, self).__init__()
# 调用 dispatcher(分发/调度器) 模块中的 connect 函数
# 第一个参数 receiver, 接收一个处理方法的名称
# 第二个参数 signal, 接收一个信号, 传入 signals(信号池) 中的某个信号
# spider_closed: 当 Spider close 的时候, 给出的信号
# 分发器调用传入方法
dispatcher.connect(self.spider_closed, signals.spider_closed)
def spider_closed(self, spider):
"""当爬虫关闭的时候, 关闭 browser 实例"""
print('{} closed execute browser quit'.format(spider.name))
self.browser.quit()