前言
由于某些原因,我需要去爬获取一些国家旅游景点的信息。
找到国家旅游局的网站,然后找到一个 5A 风景区目录。
于是去 pyspider 的 demo 页新建一个项目:5stat,就去爬了。
分析页面
网页比较特殊,看起来是用 dotnet 写的,翻页是按钮调用 js 代码实现的。跳转后还是同一个网址。
这里就要用到 pyspider 支持的页面载入后运行 js 脚本的功能。
先分析翻页按钮干了什么。
如下图,调用一个名为 __doPostBack
的函数。
在页面上寻找这个函数,看到函数体如下:
1 | var theForm = document.forms['form1']; |
函数将 theForm
里面的 __EVENTTARGET
值设置为 PageNavigator1$LnkBtnNext
之后就提交了。
找到 theForm
对应的元素,看见有三个隐藏域, __EVENTTARGET
、__EVENTARGUMENT
和 __VIEWSTATE
。
附近还有一个隐藏域 __EVENTVALIDATION
。看名字就觉得要提交。
于是试试只提交这三个值看看会不会报错。
在 chrome 上安装 postman 这个应用,打开。
修改方式为 POST,填上地址和三个域的值,send。
OK,返回了正确的页面,也就是可行了。
爬虫脚本
嗯 pyspider 的爬虫脚本怎么写就不详述了,不会的看文档。
着重列出爬虫执行的 js 脚本的功能。
1 | function() { |
如此一来在回到爬虫脚本中的时候就能得到下一页跳转的参数了。
奇怪的地方来了
因为 pyspider 的文档说明对于每个项目内的相同网址会忽略,于是按照教学提示给网址加了个 #
。很明显这样的网址不会改变请求的参数(使用一些其他技术的情况下除外)。
之后不再使用这个方法,因为 pyspider 判断是否同网址实质上是简单地将网址 md5 一下生成任务 id,以此来判断是否同一个爬虫任务。后来用的方法是直接重写任务 id 的生成。
然而在爬下来的数据中却发现有除了旅游地点外的酒店信息。
原来同一个页面也有五星级饭店的信息。如下图,注意最后有一个 #
。
点击后跳转到一个网址:http://www.cnta.gov.cn:8000/Forms/TravelCatalog/TravelCatalogList.aspx?catalogType=hotel&resultType=%u4E94 的页面。
看起来跟旅游地点差不多,新建一个项目 5hotel,直接复制粘贴之前的代码,就是改了一下网址。
期间还将任务 id 的生成重写了一下,这样即使请求同一个网址也没问题了。
然而运行的结果却失败了。
在 content 中很明显看出页面获取不全,然而代码是直接复制的,页面也是相同结构的,为什么会出现这个问题呢?
然后我就被困扰了两天,接着就没在去管,盘算以后自己实现个爬虫再爬好了。
转机
今天我再上去看,爬 5A 风景区的项目一直稳定运行。
五星级饭店的却还是无法抓取全部页面。
然后我鬼使神差地给网址加了一个 #
。网址从:
www.cnta.gov.cn:8000/Forms/TravelCatalog/TravelCatalogList.aspx?catalogType=hotel&resultType=%u4E94
变成
www.cnta.gov.cn:8000/Forms/TravelCatalog/TravelCatalogList.aspx#?catalogType=hotel&resultType=%u4E94
然后就能爬了!!!
shenmegui???!!!
我也搞不清楚究竟是 pyspider 的问题还是 phantomjs 的问题还是 dotnet 的问题了。