抓取内容介绍
github地址:github.com/jiahaoabc/c…
思科是一家世界500强企业,尤其在通讯领域是顶尖的存在,它是全球领先的互联网解决方案供应商,提供了企业网络、数据中心、安全协作以及物联网(loT)等解决方案。在思科的官网提供了关于交换机、路由器、无线和有线网络或其他的一些产品的产品手册、白皮书、产品简介、设计指南、解决方案等等文件。
本文的目的是抓取上述文件,将这些文件的标题、大小、所在url以及文件本身存入MongoDB数据库。

网站抓取分析
抓取页面寻找
一般而言,我们要抓取的数据不必要从一个网站的首页开始,定位到数据存在的子页面直接抓取会更加方便,思科官网是英文的不方便我们分析,转换为中文页面,然后对官网层层嵌入查找,找到我们需要的抓取的企业网络资料页如下图所示,然后抓取交换机、路由器、无线、网络以及其它这些标签下的所有pdf文件(所有文件均为pdf格式存在)

难点分析
总体分析了一下这个网站和这些文件的加载方式,数据量不大,难度也一般吧,不过有两个和其他网站不同的而且挺有意思的点。本来以为像其他网站的的pdf文件一样,只要找到每个文件的URL点击便会下载到本地,就可以直接抓取下来保存。但是每次点击一个pdf文件,都跳转到一个不同URL的注册页面。

输入注册信息后,点击下载白皮书,然后又跳到了如下的一个页面,需要再次点击下载,最后在此页面里点击下载才能得到需要的pdf文件。

所以,一个有意思的点就在于这个网站每次需要下载一个pdf文件时都需要注册一次,而且每次注册的页面URL都不同,不像别的网站注册登录后就一劳永逸了。
另外一个有意思的点在于注册完点击下载后,不是直接将pdf文件下载下来,而是又跳到一个新的下载页面,在之前页面的页面控制台下也找不到和这个URL相关的信息,这个URL和pdf文件的URL似乎也没有半毛钱关系,因为不提供登录方法,无法维持自己客户机与思科服务器之间的连接,所以当再次访问上面的下载页面链接‘s177775138.t.eloqua.com/e/f2’时直接报错。

代码实现
用框架pyspider和pycharm写了两份代码,这里就讲一下pyspider的实现方式。
首先爬虫从pdf分布的列表页开始进入:
@every (minutes=24 * 60)
def on_start(self):
self.crawl ('https://www.cisco.com/c/m/zh_cn/about/solutions/enterprise-networks/index.html',
callback=self.index_page, validate_cert=False)进入列表页后开始解析出每个pdf文件的url,同时提取出每个url里的oid值(为什么要取这个,后面说),解析出来后,将oid值回调给login函数进行注册
@config (age=10 * 24 * 60 * 60)
def index_page(self, response):
# 解析页面所有pdf文件url,获取每个url对应的oid值并返回给注册函数login()
for each in response.doc ('td > a').items ():
#用正则提取两种不同url的oid值
result_one = re.findall (".*en/(.*).html.*", each.attr.href)
result_two = re.findall (".*vertical/(.*).html.*", each.attr.href)
if (result_one):
self.crawl (each.attr.href, callback=self.login, save={'a': result_one}, validate_cert=False)
oid = result_one
elif (result_two):
self.crawl (each.attr.href, callback=self.login, save={'a': result_two}, validate_cert=False)
oid = result_two当执行此函数时,我们可以看到一共有140个pdf的url解析出来了(数量和实际数量一样)

抓取到url后,就像我们之前分析的那样,点击pdf文件,然后就跳转到一个注册页面,此时需要开始post表单进行注册,通过抓包分析,发现post表单有很多字段,不确定cisio服务器是对哪些字段进行检测,所以把所有字段都加入进去是最保险的,其中有一个变化的字段—oid,发现是隐藏在pdf的url中。仔细分析,虽然每次的注册页面不同,但是只需要对‘s177775138.t.eloqua.com/e/f2’这个URL进行post提交表单即可完成注册,然后跳转到下载页面,代码如下:
def login(self, response):
# post注册登录,登录后的页面返回给detail_page处理
url = response.url
Oid = response.save[ 'a' ]
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36',
'Host': 's177775138.t.eloqua.com', 'Origin': 'https://www.cisco.com', }
post_data = {
'elqFormName': 'GRSDynamicOfferForm',
'elqSiteId': '177775138',
'elqCampaignId': '',
'lastName': '莫叹',
'emailAddress': '*******',
'busPhone': '********',
'company': 'juejin',
'dropdownMenu': '北京',
'jobLevel1': 'CXO/Executive',
'department': 'MIS/IT - Applications Dev',
'dropdownMenu2': 'Chemical & Petroleum',
'opt_in': 'on',
'updatedby': 'Form - submit',
'emailName': '',
'FORMID': '3473',
'hiddenField3': '',
'hiddenField5': '177775138',
'CCID': 'cc000069',
'DTID': 'odicdc000510',
'OID': Oid, #这个时变化的,需要填入pdf的url里的oid值
'ECID': '3495',
'keycode1': '',
'GCLID': '', 'keywords': '',
'campaign': '', 'countrySite': '', 'creative': '', 'position': '', 'placement': '', 'referingSite': '',
'search': '', 'hiddenField': '', 'hiddenField2': 'CHINA', 'offerName': '', 'offerSize': '', 'offerURL': '',
'offerURL1': ''}
self.crawl ('https://s177775138.t.eloqua.com/e/f2', callback=self.detail_page, save={'i': Oid}, method='POST',
data=post_data, headers=headers, validate_cert=False)最后,到了下载页面,对pdf文件的大小、标题、内容进行解析,基本字段信息存入mongodb数据库,pdf文件存入本地文件夹。
@config (priority=2)
def detail_page(self, response):
# 解析每个pdf对应的标题、大小、和url存入mongodb,将pdf下载到本地
i = response.save[ 'i' ]
#标题
title = response.doc ('.asset-desc').text ()
#大小
size = response.doc ('.asset-info').text ()
#pdf所在url
pdf_url = response.doc ('.download-button').attr.href
#pdf内容
content = requests.get (pdf_url).content
item = {}
item[ "pdf_title" ] = title
item[ "pdf_size" ] = size
item[ "pdf_url" ] = pdf_url
# pdf_file_path = os.path.abspath ('') + str (i) + '.pdf'
pdf_file_path = 'E:\cisio_demo\cisio_pdf\%s.pdf'%str(i)
print(pdf_file_path)
with open (pdf_file_path, 'wb') as f:
f.write (content)
print(item)
client = pymongo.MongoClient (host='localhost', port=27017)
db = client.test
collection = db.cisco_pyspider
collection.insert (item)pyspider输出信息如下:

最后,我们看下pyspider的抓取进程和抓取内容



可以看出,pyspider这个框架还是挺好用的,三个函数,几十行代码即可抓取到思科官网的资料,虽然需要频繁注册,但这对于分布式的pyspider框架而言,自己本身的特点就是快,写好抓取和解析规则后,无惧这类频繁注册的网站。