不知不觉这个系列就已经写到了第十篇,如果你跟着前面教程一步一步来,我想你对于scrapy的熟练的程度已经超过了很多人了,这个时候你可能会思考,如果我自己去写这样一个爬虫框架,我会怎么来写,如果是我,我对于队列,数据库的解析又应该怎么来处理呢。如果你能深入到这样的一个地步,我想你一定会进步很快,带着问题去学东西始终是最快的。好了,又啰嗦一些,我们进入今天的主题,关于js的解析。
关于动态内容的解析,对于各个爬虫新手来说一直是一个山,因为自己没有思路,所以大部分时候都被这个大山挡住了前进的脚步(ps:如果你系统的做过web前端或者后端,对于学习爬虫会有十分大的帮助)
通常来说,对于js的动态内容一般两种解法
分析请求的接口,得到数据直接操作(70%的情况可以这样操作)
使用js的环境来处理
这里,js的环境分为两种,一种是有界面的,一种是无界面的,有界面的可以参考selenium ,splinter 这些解决方案或多或少都会打开一个浏览器窗口,不利于进一步的操作。
另外一种就是大名鼎鼎的phantomjs,应用很多,不过和scrapy结合不够紧密。那scrapy有没有官方的操作方式呢?答案显然有的
先上github的地址:===>scrapyjs<====
因为是基于splash: ===>splash<====
关于安装的过程,我就不安利了,按照官方提供的文档操作就可以了。(前提条件是你对docker有熟悉的感觉)
1 |
docker run -p 5023:5023 -d -p 8050:8050 --name=splash_server -p 8051:8051 scrapinghub/splash |
-d 是以fork的方式运行,–name指定容器名字,-p 绑定端口 ,ok,docker已经运行起来了,那我们怎么访问呢?别急,我们先看看docker 的ip地址是多少
1 2 |
± |master ✓| → boot2docker ip 192.168.59.103 |
然后我们直接访问http://192.168.59.103:8050/
可以看到scrapyjs服务已经起来了
比如你们一直想爬的微信数据的抓取方式,我们可以在render me里面直接输入URL:
http://weixin.sogou.com/weixin?type=2&query=%E4%BB%8A%E5%A4%A9&ie=utf8
然后出来的结果:
结果已经很明显的出来了,javascript render出来的内容,还能系统的反应出来统计的内容,根据内容我们可以进一步的过滤出来不要的内容,比如css,比如图片。
那在scrapy中我们怎么写呢?
直接上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# -*- coding: utf-8 -*- from scrapy.http import Request from scrapy.spiders import Spider from scrapy.http.headers import Headers import json from scrapy.log import logger class WeiXinSpider(Spider): name = 'weixin' # main address since it has the fun list of the products start_urls = [ 'http://weixin.sogou.com/weixin?page={}&type=2&query=%E4%B8%AD%E5%9B%BD'.format(a) for a in xrange(1,10) ] allowed_domains = [ 'sogou.com' ] def __init__(self, *args, **kwargs): super(WeiXinSpider, self).__init__(*args, **kwargs) RENDER_HTML_URL = "http://192.168.59.103:8050/render.html" def start_requests(self): #text/html; charset=utf-8 for url in self.start_urls: body = json.dumps({"url": url, "wait": 5,'images':0,'allowed_content_types':'text/html; charset=utf-8'}) headers = Headers({'Content-Type': 'application/json'}) yield Request(self.RENDER_HTML_URL, self.parse, method="POST", body=body, headers=headers) pass def parse(self, response): self.logger.info('now you can see the url %s' % response.url) div_results = response.xpath('//div[@class="results"]/div') if not div_results: logger.error(msg='there is not any body in the %s' % response.body) return for div_item in div_results: title = div_item.xpath('descendant::div[@class="txt-box"]//h4//text()') if title: txt = ''.join(title.extract()) yield {'title':txt} |
输出的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
{'title': u'\n\u3010\u672c\u671f\u9884\u544a\u3011APEC\u670d\u88c5\u8bbe\u8ba1\u5e08\u5982\u4f55\u5c55\u793a\u4e2d\u56fd\u670d\u9970\u4e4b\u7f8e?\n'} 2016-03-07 21:34:15 [scrapy] DEBUG: Scraped from <200 http://192.168.59.103:8050/render.html> {'title': u'\n\u3010889\u4f53\u575b\u5feb\u62a5\u3011\u63d0\u524d\u51fa\u7ebf!\u4e2d\u56fd\u5973\u8db31-0\u97e9\u56fd\u65f6\u96948\u5e74\u91cd\u8fd4\u5965\u8fd0\u4f1a\n'} 2016-03-07 21:34:15 [scrapy] DEBUG: Scraped from <200 http://192.168.59.103:8050/render.html> {'title': u'\n\u4e2d\u56fd\u6240\u6709\u8001\u4e2d\u533b\u7684\u96c6\u4f53\u7ed3\u6676,\u6700\u597d\u80cc\u4e0b\u6765!\n'} 2016-03-07 21:34:15 [scrapy] DEBUG: Scraped from <200 http://192.168.59.103:8050/render.html> {'title': u'\n\u4e2d\u56fd\u91d1\u6728\u540c\u6e90\u5802\u6da6\u517b\u9aa8\u9ad3\u7684\u9886\u822a\u8005\n'} 2016-03-07 21:34:15 [scrapy] DEBUG: Scraped from <200 http://192.168.59.103:8050/render.html> {'title': u'\n2016\u5e74\u4e2d\u56fdVR\u884c\u4e1a\u5e02\u573a\u73af\u5883\u559c\u5fe7\u53c2\u534a \u5934\u6761\u6570\u8bfb\n'} 2016-03-07 21:34:15 [scrapy] DEBUG: Scraped from <200 http://192.168.59.103:8050/render.html> {'title': u'\n\u94ff\u9535\u73ab\u7470 \u534e\u4e3d\u7efd\u653e\u4e28\u8d3a\u4e2d\u56fd\u5973\u8db3\u6210\u529f\u664b\u7ea72016\u91cc\u7ea6\u5965\u8fd0\u4f1a\n'} 2016-03-07 21:34:15 [scrapy] DEBUG: Scraped from <200 http://192.168.59.103:8050/render.html> {'title': u'\n\u5168\u7403\u5341\u4e2a\u6700\u5bb9\u6613\u53d1\u751f\u4e00\u591c\u60c5\u7684\u5730\u65b9 \u4e2d\u56fd\u7adf\u662f\u8fd9\u91cc!\n'} 2016-03-07 21:34:15 [scrapy] DEBUG: Scraped from <200 http://192.168.59.103:8050/render.html> {'title': u'\n\u8d70\u8fdb\u4e2d\u5c71\u5927\u5b66 \u5e9e\u4e2d\u82f1\u8c08\u4e2d\u56fd\u4e0e\u4e16\u754c\u79e9\u5e8f\n'} 2016-03-07 21:34:15 [scrapy] INFO: Closing spider (finished) 2016-03-07 21:34:15 [scrapy] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 4986, 'downloader/request_count': 9, 'downloader/request_method_count/POST': 9, 'downloader/response_bytes': 352723, 'downloader/response_count': 9, 'downloader/response_status_count/200': 9, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2016, 3, 7, 13, 34, 15, 332505), 'item_scraped_count': 89, 'log_count/DEBUG': 100, 'log_count/ERROR': 2, 'log_count/INFO': 16, 'response_received_count': 9, 'scheduler/dequeued': 9, 'scheduler/dequeued/memory': 9, 'scheduler/enqueued': 9, 'scheduler/enqueued/memory': 9, 'start_time': datetime.datetime(2016, 3, 7, 13, 33, 18, 174402)} 2016-03-07 21:34:15 [scrapy] INFO: Spider closed (finished) |
这样是不是很方便的解决了javascript 各种麻烦?那有没有不方便的地方呢?当然有,你交给渲染引擎来操作这些内容 ,那就要速度与性能的损耗,如果在大规模的抓取中,就要考虑splash的集群了,单独的集群来解析这些动态内容。不用想,各大搜索引擎也是这样类似的做法,没有区别的。
5555,这个生成不出来网易云的关注列表.而且一次载入要20-30s左右 QAQ,鱼哥,还有什么好办法么
请问这个scrapy-splash在windows不能使用么?
可以,因为可以基于docker ,而docker 是可以跨平台的。
我按照教程上的安装了,anaconda找不到对应的包,pip能安装,但是docker run...不能运行,跟python的版本有关系么
docker是个软件需要另外安装么?
求教程发布顺带写下运行环境和软件,,,,Thank you
我在win和ubuntu都正常跑过了,docker用最新的就可以, download镜像就可以正常使用。
https://www.docker.com/
你好 scrapy-splash 做分布式爬虫,scrapy-splash 只提供渲染功能 ,还是提工渲染加网络请求,也就是说目前网站识别到的是爬虫的IP还是docker服务器的IP
你看请求的顺序 A->B(渲染和再次请求)->网站 ,所以网站拿到的就是B的IP,B对外只有一个IP,就是他本机的IP
相当于部署scrapy-splash的机器是代理服务器哈
嗯,正解,渲染的是独立的IP
± |master ✓| → boot2docker ip
192.168.59.103
这个命令 MacOS 上没有。我跑起来后直接是 127.0.0.1
早期的docker 在mac上运行是以vm 为载体运行的,所以这个ip是老版本的做法。
大佬好!
我在树莓派4b (操作系统是Debian Buster with Raspberry Pi Desktop 芯片 arm7l ) linux 通过docker安装镜像并试图运行splash,结果报错,
具体如下:
# sudo docker run -it -p 8050:8050 --rm scrapinghub/splash
standard_init_linux.go:207: exec user process caused "exec format error"
确定 docker 是不是能正常运行在 树莓派4b 上,感觉更像是docker的问题