准备工作:
先在终端重启下docker服务:
sudo service docker start
然后让Docker容器以守护态运行,这样在中断远程服务器连接后,不会终止Splash服务的运行。
docker run -d -p 8050:8050 scrapinghub/splash
把要爬的网站先输进去,点下render,让splash开始渲染。
如果像上图这样,那也不必执行爬虫操作,浏览器都无法渲染,python还操作个锤子。
-_-!
可能是网络不太好,再点一下,如果还是这样婶,就重启下网络
service network restart
重启网络后再点一下,看是否OK。如果还是不行,就执行下重启电脑这个大杀器。
为什么说重启电脑是大杀器呢?因为重启电脑后真的是可以加载了:
正式开始:
既然是要爬取多页,那就先定位下翻页的元素,如下图所示,点向右的箭头可以控制翻页,那就定位该元素,写出个css选择器出来。也可以让浏览器给copy,但这家伙copy出来的东西有时候不太准确,还需要自己加以判断。
有了这个元素写一点js代码就OK了。
# 模拟点击采用js的方式
script = """
function main(splash, args)
splash.images_enabled = false
assert(splash:go(args.url))
assert(splash:wait(1))
js = string.format("document.querySelector('div.paginationjs-pages > ul > li.paginationjs-next.J-paginationjs-next a').click();", args.page)
splash:runjs(js)
assert(splash:wait(5))
return splash:html()
end
"""
上面代码的意思,很显然嘛,这里不做过多介绍。
好了好了,说一哈:
1.images_enabled = false不加载图片,因为加载图片会让网页加载变慢,默认是加载的,需要设置false,才是不加载;
2.go(),请求链接;
3.wait(),相当于python中的sleep;
4.js中的代码在本篇中表示定位到翻页的那个右箭头,然后点击一下,后面跟着的args.page至关重要,如果没有它,就无法实现翻页,这里它是一个伏笔,等待下面的代码调用;
5.runjs(),执行上面的JavaScript代码;
6.html(),返回html源代码。
然后start_requests长这个样子:
def start_requests(self):
for page in range(1, 5):
url = self.base_url
yield SplashRequest(url, callback=self.parse, endpoint='execute',
args={'lua_source': script, 'page': page, 'wait': 10})
完整代码如下:
# -*- coding: utf-8 -*-
import scrapy
from scrapy_splash import SplashRequest
from caigou.items import CaigouItem
# 模拟点击采用js的方式
script = """
function main(splash, args)
splash.images_enabled = false
assert(splash:go(args.url))
assert(splash:wait(1))
js = string.format("document.querySelector('div.paginationjs-pages > ul > li.paginationjs-next.J-paginationjs-next a').click();", args.page)
splash:runjs(js)
assert(splash:wait(5))
return splash:html()
end
"""
class ZfcaigouSpider(scrapy.Spider):
name = 'zfcaigou'
allowed_domains = ['www.zjzfcg.gov.cn']
base_url = 'http://www.zjzfcg.gov.cn/purchaseNotice/index.html?categoryId=3001'
def start_requests(self):
for page in range(1, 5):
url = self.base_url
yield SplashRequest(url, callback=self.parse, endpoint='execute',
args={'lua_source': script, 'page': page, 'wait': 10})
def parse(self, response):
# print(response.body.decode("utf-8"))
infodata = response.css(".items p")
for infoline in infodata:
caigouitem = CaigouItem()
caigouitem['city'] = infoline.css(".warning::text").extract()[0].replace("[", "").replace("·", "").strip()
caigouitem['issuescate'] = infoline.css(".warning .limit::text").extract()[0]
caigouitem['title'] = infoline.css("a .underline::text").extract()[0].replace("]", "")
caigouitem['publish_date'] = infoline.css(".time::text").extract()[0].replace("[", "").replace("]", "")
yield caigouitem
爬取结果:
因为自定义只爬5页,有60个数据,说明爬成功了,开心,嘻嘻。
注:
wait()
在脚本内调用的wait()方法类似于Python中的sleep(),其参数为等待的秒数。当Splash执行到此方法时,它会转而去处理其他任务,然后在指定的时间过后再回来继续处理。
main()
main()方法的第一个参数是splash,这个对象非常重要,它类似于Selenium中的WebDriver对象,我们可以调用它的一些属性和方法来控制加载过程。接下来,先看下它的属性。
args
该属性可以获取加载时配置的参数,比如URL,如果为GET请求,它还可以获取GET请求参数;如果为POST请求,它可以获取表单提交的数据。Splash也支持使用第二个参数直接作为args
images_enabled
此属性可以设置图片是否加载,默认情况下是加载的。禁用该属性后,可以节省网络流量并提高网页加载速度。但是需要注意的是,禁用图片加载可能会影响JavaScript渲染。因为禁用图片之后,它的外层DOM节点的高度会受影响,进而影响DOM节点的位置。因此,如果JavaScript对图片节点有操作的话,其执行就会受到影响。
另外值得注意的是,Splash使用了缓存。如果一开始加载出来了网页图片,然后禁用了图片加载,再重新加载页面,之前加载好的图片可能还会显示出来,这时直接重启Splash即可。
go()
该方法用来请求某个链接,而且它可以模拟GET和POST请求,同时支持传入请求头、表单等数据
runjs()
此方法可以执行JavaScript代码,它与evaljs()的功能类似,但是更偏向于执行某些动作或声明某些方法。
完整项目请参考:https://github.com/hfxjd9527/caigou