1.集成selenium
下载中间件的 process_request 方法 ,它有四种返回值:
process_request() should either:
return None,
return a Response object,
return a Request object,
or raise IgnoreRequest.
-
可以返回 None,scrapy 会继续调用其他下载中间件继续处理请求,一般修改代理 IP 或者修改请求头就使用这种方式
-
可以返回 Response 对象,scrapy 会停止调用其他下载中间件,并且直接返回此 Response 对象
-
可以返回 Request 对象,scrapy 会停止调用其他下载中间件,遇到需要手动重定向时或者需要发送其他请求时使用
-
可以引发一个异常,scrapy 会自动调用异常处理函数 process_exception 来处理,如果没有人来处理,那么请求将会被丢掉并且不进行记录
1.1selenium在scrapy中的使用流程:
1.重写爬虫文件的构造方法,在该方法中使用selenium实例化一个浏览器对象(因为浏览器对象只需要被.实例化一次)
2.重写爬虫文件的closed(self,spider)方法,在其内部关闭浏览器对象。该方法是在爬虫结束时被调用
3.重写下载中间件的process_response方法,让该方法对响应对象进行拦截,并篡改response中存储的页面数据
4.在配置文件中开启下载中间件
class WangyiSpider(RedisSpider):
name = 'wangyi'
#allowed_domains = ['www.xxxx.com']
start_urls = ['https://news.163.com']
def __init__(self):
#实例化一个浏览器对象(实例化一次)
self.bro = webdriver.Chrome(executable_path='/Users/bobo/Desktop/chromedriver')
#必须在整个爬虫结束后,关闭浏览器
def closed(self,spider):
print('爬虫结束')
self.bro.quit()
2.scrapy-selenium安装
pip install scrapy-selenium
github:https://github.com/clemfromspace/scrapy-selenium
安装完成后,需要安装一个Chrome的driver.选择和自己的 Chrome 版本匹配的 driver 下载下来解压到 Chrome 的 Application 目录中即可。(位置自己定,但需要和配置文件统一)
2.1配置文件Settings.py
from shutil import which
SELENIUM_DRIVER_NAME = 'chrome'
SELENIUM_DRIVER_EXECUTABLE_PATH = which(r'C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe')
SELENIUM_DRIVER_ARGUMENTS = [] # '--headless' if using chrome instead of firefox
为了方便调试,这里不使用无头参数。
添加下载中间件到配置文件。
DOWNLOADER_MIDDLEWARES = {
'scrapy_selenium.SeleniumMiddleware': 800 # 这里的数值要大一些,因为中间件返回响应对象后就不会调用后续的下载中间件了,所以要保证这个中间件是最后一个被调用的
}
3.使用selenium
3.1爬虫程序
如果不设置等待的话,动态加载没有完成,在网页部分加载完成后就会直接返回get函数的内容。所以selenium 提供了 WebDriverWait 类来实现自动等待,等某个需要的元素被加载出来 get 函数才返回。
import scrapy
from scrapy_selenium import SeleniumRequest
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
class AntiSpider(scrapy.Spider):
name = 'antispider'
def start_requests(self):
urls = ['https://antispider.scrape.center/']
for a in urls:
yield SeleniumRequest(url=a, callback=self.parse, wait_time=3, wait_until=EC.presence_of_element_located((By.CLASS_NAME, 'm-b-sm')))
def parse(self, response, **kwargs):
print(response.text)
input()
input 函数是为了让爬虫暂时停下来,方便查看浏览器状态,默认状态下下载队列消耗完爬虫会自动停止运行,浏览器也会一并退出,不利于调试,当然,打断点也可以达到同样的目的。
3.2中间件
class MyDownloadMiddleware(SeleniumMiddleware):
def __init__(self, driver_name, driver_executable_path, driver_arguments,
browser_executable_path):
super(MyDownloadMiddleware, self).__init__(driver_name, driver_executable_path, driver_arguments,
browser_executable_path)
self.driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})"""
})