scrapy

根据页面响应获取动态页面信息

之前写了一篇文章写了如何用splash结合scrapy爬取动态页面的信息,不可否认,splash的功能是很强大的,能够方便的获得加载js的页面,但是在测试的过程中我发现了splash的一些问题。

  1. 由于网络的不稳定导致页面的响应时间可能非常长,因此整体爬虫的时间会大幅延长,且不可控。并且因此导致更新时间间隔加长。
  2. 长时间运行splash对服务器压力较大,加上由响应时间过长造成的任务积压,服务器会变得卡顿和不稳定。

在经过对网站功能和服务器资源的分析后,我摒弃使用splash,转而对每个需要访问的页面通过浏览器工具分析其页面的响应。因为我们所需爬取的页面数量是有限的,但是我们需要高频率地去访问这些页面,因此要尽可能减少爬取过程中消耗的时间和资源,把工作做在前面。可以利用Chrome或者Firefox的Debug工具,在network选项里查找页面载入时发送了哪些请求,然后找到我们需要的内容查看Request URL. 这样,我们只需要把scrapy里爬取的网页地址换成这个URL,然后根据响应信息的格式(通常是json)进行处理。如此一来,整个爬取页面的过程会大大加快,而服务器也能稳定运行了。

scrapy-splash爬取动态网站

最近网站的进展受到了极大的阻挠,国内几大直播网站(斗鱼,虎牙,战旗,熊猫,龙珠)都用scrapy爬取成功了,但是还有两家(全民,火猫)一直都爬不出来。一开始我是很奇怪的,明明可以用firebug查看到、并且能用Xpath Checker找到所需的信息,为什么scrapy一直失败呢。问题的突破点在于,全民tv的spider并不是完全爬不出来,而是能爬出来一些我不知道是什么的东西。然而今天我无意中查看全民的源码时,发现源码里是没有当前直播的信息的,而恰好有scrapy爬出来的东西。顺藤摸瓜,我才意识的问题的关键在于全民和火猫是动态网站,更令我惊奇的是之前爬取的都是静态网站。好吧,原谅我这么菜,这么久才知道。

知道问题的原因就比较好解决了,关于scrapy爬取动态网站的方法网上有许多教程,这里就大概的说一下。主要有两种方法来获取js渲染之后的页面:

  1. Selenium
  2. Splash

第一种是模拟用户使用浏览器的操作,需要和浏览器配合使用,考虑到服务器上安装浏览器的问题,我选择了第二种。每次安装新的东西都要折腾一段时间,splash也是如此,反正先按官网的说明来,出现什么问题就搜什么问题。好在装好之后,配合scrapy还是比较简单的。首先在settings.py里添加一些属性,然后启动splash:

1
docker run -p 5023:5023 -p 8050:8050 -p 8051:8051 scrapinghub/splash

可以通过访问 (http://localhost:8050/) 来查看js渲染后的页面。
然后只需要在原有的spider上加上一段代码即可:

1
2
3
4
5
6
7
8
9
10
11
import scrapy
from scrapy_splash import SplashRequest
class MySpider(scrapy.Spider):
# ...
def start_requests(self):
splash_args = {
'wait': 0.5,
}
for url in self.start_urls:
yield SplashRequest(url, self.parse, endpoint='render.html', args=splash_args)
# ...

基本就是这样,接下来还要在服务器上再安装一下splash,祝我好运。

scrapy 中文乱码与utf-8

记录一下刚才解决的有关scrapy中文乱码问题。

之前在mac上运行scrapy的时候没有关心过这一点,可能是系统默认字符就是utf-8。搬到linux服务器上之后会出现如下的错误。

1
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 96-106: ordinal not in range(256)

而字符串会变成这样。

1
u'\u98ce\u6b66\u0416\u9f99\u884c'

经过查找资料和测试,需要修改的地方有两个。一是建表的时候,需要在create table之后加上

1
DEFAULT CHARACTER SET = utf8

二是在连接到数据库时,在MySQLdb.connect里加上

1
charset ='utf8'

执行这两步后,即可正常显示中文。

————————–BTW————————–
在做php显示的时候也遇到了乱码的问题,就不另开贴了。在连接到数据库后加上下面的语句即可。

1
mysqli_set_charset($conn,"utf8");

scrapy再安装

记录一下此刻我复杂的心情。

为什么会再安装呢?因为之前是在本机上装的,现在要在服务器上再装一次。本以为有过一次经验的我会顺风顺水,结果是图样图森破,不过挣扎了一晚上总算是把scrapy给装上了。本来想记录一下出现的问题及解决方法,但是问题太多实在记不住了,而且出现的问题和第一次的也完全不一样。与其记住一次问题的解决答案,不如掌握解决问题的方法(才不是因为脑子不好记不住呢,哼唧)。下一次安装scrapy的时候应该也会出现一万个问题吧,只要不断的把出现的问题丢给google,相信问题一定会解决的😂。

scrapy与crontab的结合

搞了一天终于能够用crontab自动运行scrapy了。

首先crontab是一款可以实现自动运行的工具,最短每分钟执行一次。由于我们需要不停的爬取网站信息,所以需要软件在后台自动运行scrapy。方法很简单,规定每到什么时间执行什么命令就可以了。

那么开始吧,把命令提交给crontab,等了一分钟、两分钟,什么也没有出现。当时我是懵b的,道理我都懂,但是为什么执行不了XD。我的crontab内容是 sh xxx.sh,xxx.sh里面就是scrapy crawl yyy。当然,xxx.sh肯定是没有执行成功的,那么干脆把crontab的内容换成 echo “Hello”吧。Of course还是什么都没有。这时注意到时不时terminal就来一句:You have new mail. 原来crontab会把每次的执行结果发邮件给我,但至少这说明crontab是好使的。但是sh还是总不成功,在网上看了很多帖子、博客,总是没有get the point. 终于,找到了关键的一句话:

1
$ export PATH=$PATH:/usr/local/bin

原因大概是这样的,crontab执行的时候找不到scrapy这个命令,而这个命令在/usr/local/bin里,所以需要加入这个路径,然后就可以正常执行scrapy了。但是还有一个问题,每分钟一封邮件,一会感觉terminal要炸了XD。这个也找到了答案,可以在 * sh xxx.sh后面加上 >> file 2>&1,输出就会写入这个file里了。最后附上清理mail的方法,不然每过一段时间都会提示有new mail。

1
2
3
$ mail
$ delete *
$ q

写的有些啰嗦,主要是想记录一下今天解决的两个问题。不用把问题交给明天的感觉真好。

scrapy安装

昨天本来应该开始学习Scrapy(一款爬虫工具)的,但是卡在Scrapy安装的过程上。究其根本,是因为Mac系统的six安装出了问题,终于在层层Google之后找到了解决办法。

首先,在使用pip install Scrapy的时候,会卡在无法uninstall six上。然后我选择了–ignore-installed six的方法,虽然不会卡住,但在运行Scrapy的时候还是会报错。然后又搜到了这篇文章,第一个答案给出了解决办法,但第二步会提示not permitted。好在在答案的回复给出了解决办法,方法就是重启到recovery mode,然后运行csrutil disable。重启之后就可以删掉six并重新安装了。安全起见,我又重启到recovery mode重新csrutil enable。至此问题基本解决。

这个问题应该只出现在mac OS上,整理一下解决方法方便以后使用。