现在大部分网页内容都是由js动态加载得到,我们如果要使用scrapy静态爬取是爬取不到内容的,所以需要引入js渲染引擎去加载js,也就是splash。
然后还要使用一个包scrapy-splash,这个包调用了splash实例的接口,用来支持scrapy做爬虫。
Scrapy-Splash uses Splash HTTP API, so you also need a Splash instance.
1、启动splash实例
文档:https://splash.readthedocs.io/en/stable/
使用docker启动 docker run -p 8050:8050 scrapinghub/splash
2、安装scrapy-splash
pip install scrapy-splash
3、在爬虫中配置
https://pypi.org/project/scrapy-splash/
https://www.jianshu.com/p/9d0c53c97850
4、常见问题
① 浏览器可以直接访问localhost:8050访问splash实例,里面可以实施渲染Lua脚本,非常方便
② splash可以渲染Lua脚本语言,支持的操作可参照官网文档,这里举例一般爬虫需要的几个功能:访问网址、添加和获取cookie, 输入框,点击按钮,添加代理等
lua = """
function main(splash, args)
barcode = args.barcode
splash:on_request( #Register a function to be called before each HTTP request.
function(request)
request:set_proxy{'36.112.xxx.xxx', 25030 , username=nil, password=nil, type='HTTP'}
end)
splash:add_cookie{"ASP.NET_SessionId", "wptayq45fqbkbu55defy3245", path="/", domain="xxx.xx.com",httpOnly=True,secure=False}
assert(splash:go(args.url))
assert(splash:wait(2))
return {
html = splash:html(),
png = splash:png(),
cookies = splash:get_cookies(),
har = splash:har(),
}
end
"""
因为使用scrapy-splash,所以我们不能用scrapy的方法来操作cookies或者使用代理,这些都需要通过Lua脚本。
③ scrapy中使用yield SplashRequest
yield SplashRequest(url, endpoint='execute', args={'lua_source': lua,'barcode':barcode,'cookie':cookie},
cache_args=['lua_source'], callback=self.parse_data)
args里带上需要添加的cookie或者其他参数比如模拟登陆就带上username和psw
④ meta里有一些key是保留的关键词,不能用!!https://docs.scrapy.org/en/latest/topics/request-response.html?highlight=timeout#std-reqmeta-download_timeout
比如proxy, Download_Timeout之类的
⑤scrapy的顺序是,默认深度优先 即
DEPTH_PRIORITY = 0
SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'
但是如果层级只有1层就不影响了。
然后由于scrapy的多线程机制,在start_request当中,并不是完全顺序执行的(结果上来说,不是按顺序获得结果的,有的结果响应快,先返回,有的结果响应慢,过了很久才返回),因为它是非阻塞的。也就是如果某一个请求还没返回,他会执行下一个请求,
并且保持正在请求的数目,即并发数等于我们配置的CONCURRENT_REQUEST。
所以如果我们要保证一个请求结束才进行下一个请求,那么我们需要开单并发,然后运行多个scrapy(有点傻)。主要还是因为我们没有使用scrapy本身的ip代理,也就无法应用
CONCURRENT_REQUESTS_PER_IP = 1 这个参数,因为我们的ip代理是通过scrapy-splash执行的,如果不用splash,我们可以直接设置每个ip并发为1。