可能很多同学看到关于动态页面的反爬(比如基于Ajax的网页)第一反应就是selenium+headless browser,这个方法好是好,然而是基于真实的浏览器,虽然没有界面,但是也占用很多内存。小型的测试用selenium的确不错,但是一旦业务量大起来了,需求复杂了,甚至需要分布式爬虫操作时,这个方法对于内存的开销实在受不了。
那么有不用selenium的方法吗?当然有,今天就教大家硬刚基于Ajax的动态页面,从js的源码里边分析,一步一步倒推出页面的产生过程,从而获取我们所需要爬取的元素。
一般来说,页面产生内容有以下几种方式:
现在我们来分析一个网站。http://pubs.rsc.org/。这是一个关于化学的论文期刊数据库网站,可以通过关键字搜索论文或者书籍等。
我们通过关键字搜索bupt,可以看到出现了31条结果。
现在的需求是抓取文章列表,我们满怀信心右键一下查看源码,ctrl+f查找文章标题开头“The fate of”,然而,我们遗憾地发现,找到了0个结果。
于是我们f12一下,通过network查看一下,注意,最开始我们是不知道数据到底是怎么动态生成的,于是在xhr和Script里边都找一遍。经过一番尝试,我们确定了数据是有Ajax动态生成的,在XHR里边找到了我们所需要的内容。
哈!这不就是我们所需要的标题吗。于是开开心心的复制这个journalresult的url打开一看:
别急,再仔细看看journalresult的header才发现这是一个post请求获得的页面,我们没传参数当然看不到正确页面。
于是,问题又来了,Form Data里边,resultcount,category,pageno都还好说,这个searchterm一大堆是啥呀。看起来毫无规律,真叫人头大。
这个时候复制一下前面的一小段,‘AAEAAAD/////AQAAAAAAAAA’,准备到source里边find一下。结果,一下子就在原始html里边找到了。对比一下,一毛一样。至此,post所属的数据也有了。
我们回头分析整理一下,整个流程是这样:
博主只展示前4步,第5步就很常规了,请大家自由发挥,以下是代码:
# -*- coding: utf-8 -*-
# @Author: Nessaj
# @Date: 2018-04-11 22:33:57
# @Last Modified by: Nessaj
# @Last Modified time: 2018-04-12 22:34:14
import requests
import re
class pubulishing(object):
"""docstring for pubulishing"""
def __init__(self,kw,page):
self.baseurl = 'http://pubs.rsc.org/en/results?searchtext='
self.kw = kw
self.api = "http://pubs.rsc.org/en/search/journalresult"
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
}
self.page = page
def get_SearchTerm_resultcount(self):
url = self.baseurl + "{0}".format(self.kw)
response = requests.get(url=url,headers=self.headers)
content = response.text
searchterm = re.search(r'\s*(.+?)\s*')
artical_list = re.findall(pat,content)
true_list=[]
# 文章标题有些格式是用html标签完成的,比如氧气O2的下角标2,这里统一处理掉
for each in artical_list:
each = each.replace('','')
each = each.replace('','')
each = each.replace('','')
each = each.replace('','')
each = each.replace('','')
each = each.replace('','')
each = true_list.append(each)
return true_list
pub=pubulishing('bupt',1)
artical_list = pub.get_artical_list()
print(artical_list)
输出是一个列表,如下图,由于是外网访问速度不是很稳定,所以用了4.7s,但是肯定比selenium的方法要快的:
这是系列文章第一篇,算是一个比较简单的动态网页解析思路过程,都看到这里了,不给个赞嘛~后续还会有破解复杂的加密算法Ajax请求的分析,敬请期待。
代码已上传gtihub,欢迎大家来吐槽,觉得有意思的可以star一下啦