小白学Python之爬虫篇(二)——隐式资源链接查找与爬取

说明

在上一篇文章中,我们对PPT网站的模板进行了爬取,该网站中,每个模板的详情网页直接包含目标资源的链接,因此只需遍历列表中的模板,依次提取链接即可,是一种十分简单的爬虫程序。对于某些稍微复杂些的网页,他们的资源链接并不会直接显示在HTML代码中,本次介绍这种略复杂网页的资源爬取。

核心思路

其实对于这种网页中资源链接的查找,我认为也并不复杂。众所周知,一个网络资源的下载是通过网络间的通讯实现的,即计算机网络中的三次握手,request和response。而我们要找到的就是代码中的request请求,其中必然包含了目标资源的链接。找出request请求是我们的主要任务,其他环节则与上一章所述基本相同。

找到网页中隐藏的目标资源链接

我们以“巨潮资讯网”为例,网站链接为:http://www.cninfo.com.cn/new/index
任意输入一个企业的代码,如600018(上港集团),获得如下界面:
小白学Python之爬虫篇(二)——隐式资源链接查找与爬取_第1张图片
本次实践的目标是:从巨潮资讯网爬取给定代码列表所代表的企业的2018年年度报告。
具体分析过程如下:
1.查看该详情网页源代码,重点关注HTML代码中是否出现“2018年年度报告”的字样。最终定位到HTML代码中的如下部分:
小白学Python之爬虫篇(二)——隐式资源链接查找与爬取_第2张图片
可以看到,网页中上港集团的公告列表是通过分页插件实现的,包括我们想要的2018年年度报告在内的公告信息并没有在HTML代码中展示,我们想要的目标资源链接(2018年度报告的PDF文件)显然也无法直接通过HTML代码找到。
我们在该网页找到“2018年年度报告”的公告,并点击进入,发现该页面有PDF文件的下载按钮,继续查看源代码,定位“下载”按钮到如下位置:
小白学Python之爬虫篇(二)——隐式资源链接查找与爬取_第3张图片
同样无法直接看到资源的链接。
2.查看网页的JS代码
网页的网络请求通常都在JS代码中实现,因此我们确定无法从HTML中获取目标链接后应继续进行下一步,查看网页JS代码。
一个HTML中可能存在多个JS文件的链接,这些JS文件的命名通常都是有规律可循的,通过分析目标区域的位置、内容,结合JS文件名称,从最有可能的JS文件看起,寻找request请求。
我们最终想要的是PDF文件的下载链接,毫无疑问我们应优先研究公告详情界面的JS代码。依次查看最底端的三个JS文件。
小白学Python之爬虫篇(二)——隐式资源链接查找与爬取_第4张图片
在notice-detail.js中发现了下载资源的链接,如图:
小白学Python之爬虫篇(二)——隐式资源链接查找与爬取_第5张图片
但是,很显然我们并不知道bulletinId和announceTime这两个参数的取值。猜测这两个参数为公告ID与公告发布时间。浏览完这个JS文件后仍然找不到这两个参数,我们明智的选择去公告列表界面寻找想要的信息,因为,点击公告标题,跳转到详情界面,必然需要包含公告ID这个参数。

在样例HTML网页中,我最终锁定了名为search_new.js的代码文件,在该文件中找到了公告列表的获取代码,如下:
小白学Python之爬虫篇(二)——隐式资源链接查找与爬取_第6张图片
可以看到代码中利用ajax发送了一个get方式的request请求,通过继续查看该文件可以获取到其中每个参数的具体内容及赋值方式,将该请求拼接成一个完整的url(不知道怎么拼接的就去了解下request的两种方式),样例如下:
http://www.cninfo.com.cn/new/fulltextSearch/full?searchkey=600018&sdate=2019-01-01&edate=2019-04-25&isfulltext=true&sortName=nothing&sortType=desc&pageNum=1
需要注意的是,此处获取到的是代码为600018的公司第一页公告的列表,response返回的内容是一系列JSON字符串,如下:
小白学Python之爬虫篇(二)——隐式资源链接查找与爬取_第7张图片
我们需要依次查看该公司每一页公告列表直至找到我们需要的“2018年年度报告”的公告,如下:
在这里插入图片描述
我们最终获取到了需要的bulletinId和announceTime这两个重要参数。

代码示例

# -*- coding: utf-8 -*-
"""
Created on Mon Dec  3 16:16:24 2018

@author: Wang
"""

import re
import requests
import hashlib
import time
import json
import os
from concurrent.futures import ThreadPoolExecutor

p = ThreadPoolExecutor(1)  # 定义线程池最多容纳30个线程
codelist = []

# 检测连接是否成功
def get_Index(url):
    respose = requests.get(url)
    if respose.status_code == 200:
        print("网站链接成功")
        #解析JSON
        res = respose.text
        data = json.loads(res)
        #获取每一界面
        for i in range(1, int(data['totalpages']) + 1):
            page_url = url[0:len(url)-1]+str(i)
            page_respose = requests.get(page_url)

            if page_respose.status_code == 200:
                page_res=page_respose.text
                page_data=json.loads(page_res)

                for item in page_data['announcements']:
                    temp=item['announcementTitle'].split(':')
                    if temp[1]=="2018年年度报告":
                        announcementId=item['announcementId']
                        timeStamp = float(item['announcementTime']/1000)
                        timeArray = time.localtime(timeStamp)
                        announcementTime=time.strftime("%Y-%m-%d", timeArray)
                        #下载链接
                        downloadUrl='http://www.cninfo.com.cn/new/announcement/download?bulletinId='+announcementId+'&announceTime='+announcementTime
                        #下载
                        announcement=requests.get(downloadUrl)
                        if announcement.status_code==200:
                            m = hashlib.md5();
                            m.update(downloadUrl.encode('utf-8'))
                            m.update(str(time.time()).encode('utf-8'))
                            #filename = r'%s.pdf' % m.hexdigest()
                            filename = r'%s.pdf' %item['secName']

                            filepath = r'D:\\report\\%s' % filename
                            with open(filepath, 'wb') as f:
                                f.write(announcement.content)
                            print("下载成功")
                            break
                        else:
                            print("无法下载")
                            break
            else:
                print("获取界面失败")
    else:
        print("无法链接")
        return

# 将文件保存
def save(ppt_url):
    ppt = requests.get(ppt_url)
    if ppt.status_code == 200:
        m = hashlib.md5();
        m.update(ppt_url.encode('utf-8'))
        m.update(str(time.time()).encode('utf-8'))
        filename = r'%s.zip' % m.hexdigest()
        filepath = r'D:\\ppt\\%s' % filename
        with open(filepath, 'wb') as f:
            f.write(ppt.content)
    else:
        print("无法下载")
        return


def main():

    f=open('codelist.txt','r')
    lines=f.readlines();
    for line in lines:
        line=line.strip().replace('\n','')
        codelist.append(line)
    f.close()
    #存储路径
    if not os.path.exists('d:/report'):
        os.makedirs('d:/report')
    for i in codelist:
        p.submit(get_Index, 'http://www.cninfo.com.cn/new/fulltextSearch/full?searchkey=%s&sdate=2019-01-01&edate=2019-04-25&isfulltext=true&sortName=nothing&sortType=desc&pageNum=1' % i)


if __name__ == '__main__':
    main()


本小节到此结束,后续如果继续研究爬虫,本文会适时更新。

你可能感兴趣的:(小白学Python之爬虫篇(二)——隐式资源链接查找与爬取)