Python网络爬虫实战:卫健委官网数据的爬取 您所在的位置:网站首页 写给朋友书信祝福语要怎么写呢 Python网络爬虫实战:卫健委官网数据的爬取

Python网络爬虫实战:卫健委官网数据的爬取

2023-04-08 12:48| 来源: 网络整理| 查看: 265

零  爬虫和反爬机制间的博弈 

 关于我跟网站反爬机制之间的各种博弈过程,我其实在另一篇博客中详细写了,可惜不知道哪儿触碰到了 CSDN 的审核机制,审查没有通过。其实也是一些失败的爬虫尝试,没什么意思。真的有人感兴趣的话可以私下加我交流。

讲道理,卫健委的网站比我想象中要难爬的多,反爬机制是真的强。

Python网络爬虫实战:卫健委官网数据的爬取_Python网络爬虫

经过无数次的 412 错误,我发现这个网站的反爬机制有以下几个特点(个人经验,总结不准确或者有遗漏的点欢迎大家补充)。

服务器在处理网络请求时是要验证 Cookie 的。Cookie 的值是动态变化的,一个 Cookie 的有效时长大概只有几十秒。访问不同的网页时会更换 Cookie ,所以通过打时间差,用一个 Cookie 爬多个网页的想法不成立。网站会检测识别并限制 Selenium 的访问,用 Selenium 访问得到的只是一个空界面。

这样的特点就意味着,我没有办法通过常规的方法来爬取该网站。

很显然,该站的 Cookie 是经过 js 加密的,其中至少包含了 3 个加密后的参数。

想要真正意义上破解其加密算法,实现数据爬取,理论上是可行的,因为加密过程是在浏览器中完成的,所有加密的代码都可以在开发者工具中看到,所以理论上,你只需要懂 js,花点功夫是可以完成破解的。(But,不建议这样去做,如果是磨练技术,可以私下研究研究,但如果是为了写爬虫而写这个,投入和产出其实是有点不成正比的,不划算。而且破解对方网站加密算法,你可是在法律的边缘试探啊!)

 

 在我一筹莫展之际,一位大佬的推荐给我一款 “神器”,成功完成了爬取,那就是 pyppeteer。

关于这个框架,多的我也不说了(主要是我也是刚接触,了解不深,详细的介绍大家可以去网上查找了解)

简单说,就是进阶版的 selenium,功能更完善,效率更高,更容易绕过反爬检测。

抱着试试看的心态,我安装了这个库,试着跑了一下。

import asyncio from pyppeteer import launch url = 'http://www.nhc.gov.cn/xcs/yqtb/list_gzbd.shtml' async def fetchUrl(url):     browser = await launch({'headless': False,'dumpio':True, 'autoClose':True})     page = await browser.newPage()     await page.goto(url)     await asyncio.wait([page.waitForNavigation()])     str = await page.content()     await browser.close()     print(str) asyncio.get_event_loop().run_until_complete(fetchUrl(url))

居然真的成功了!

Python网络爬虫实战:卫健委官网数据的爬取_Python网络爬虫_02

至此,借由 Pyppeteer 这个神器,卫健委官网的反爬机制终于算是可以绕过去了。

下面我会详细介绍爬取的过程。

 

贰 卫健委官网文章的爬取

1. 安装必要的库 

我们的爬虫用到的库是 pyppeteer 和 BeautifulSoup 库,下面是安装指令(具体安装方法网上教程很多)

pip install pyppeteer pip install bs4

如果运行以下代码没有报错,说明安装成功。

import asyncio from pyppeteer import launch from bs4 import BeautifulSoup

 

2. 分析目标网站

由于经过前面的尝试,我们已经可以成功绕过网站的反爬机制,所以这里可以直接放心的分析网页结构了。

第一页 : http://www.nhc.gov.cn/xcs/yqtb/list_gzbd.shtml

第二页 : http://www.nhc.gov.cn/xcs/yqtb/list_gzbd_2.shtml

第三页 : http://www.nhc.gov.cn/xcs/yqtb/list_gzbd_3.shtml

首先观察分析网站的 URL 规则,我们可以发现,除第一页之外,其他页码的 URL 都有显著的规律——URL 中的数字对应了当前的页码,也就是说,是通过 URL 来实现翻页的。

Python网络爬虫实战:卫健委官网数据的爬取_Python网络爬虫_03

如上图所示,我们通过 F12 召唤出来的开发者工具可以看到,所有的文章,都存放在一个 class 为 zxxx_list 的 ul 标签下,其中每一个 li 标签对应着一篇文章(除了中间有部分 class="line" 的 li 标签是作为分割线)。

文章的标题存放在 li 标签下, a 标签的 title 属性里,文章的链接存放在 a 标签的 href 属性里。发表时间存放在 li 标签下,span 标签的 text 里。

Python网络爬虫实战:卫健委官网数据的爬取_Python网络爬虫_04

然后分析文章详情界面,正文部分存放在一个 id 为 xw_box 的 div 标签下(div 下的 众多 p 标签中,不过不用去管那些 p 标签,直接取 div 的 text 即可)。

至此,网站界面分析完成。

 

3. 开始编码爬取

首先导入需要的库。

import os import asyncio from pyppeteer import launch from bs4 import BeautifulSoup

将 pyppeteer 的操作封装成 fetchUrl 函数,用于发起网络请求,获取网页源码。

async def pyppteer_fetchUrl(url):     browser = await launch({'headless': False,'dumpio':True, 'autoClose':True})     page = await browser.newPage()     await page.goto(url)     await asyncio.wait([page.waitForNavigation()])     str = await page.content()     await browser.close()     return str def fetchUrl(url):     return asyncio.get_event_loop().run_until_complete(pyppteer_fetchUrl(url))

然后我们根据 URL 构成规则,通过 getPageUrl 函数构造每一页的 URL 链接(博主爬取的时候,网站的文章只有 7 页,所以这儿设置页数为 range(1, 7),大家可以根据自己爬取时候的实际情况进行调整)。

def getPageUrl():     for page in range(1,7):         if page == 1:             yield 'http://www.nhc.gov.cn/xcs/yqtb/list_gzbd.shtml'         else:             url = 'http://www.nhc.gov.cn/xcs/yqtb/list_gzbd_'+ str(page) +'.shtml'             yield url

通过 getTitleUrl 函数,获取某一页的文章列表中的每一篇文章的标题,链接,和发布日期。

def getTitleUrl(html):     bsobj = BeautifulSoup(html,'html.parser')     titleList = bsobj.find('div', attrs={"class":"list"}).ul.find_all("li")     for item in titleList:         link = "http://www.nhc.gov.cn" + item.a["href"];         title = item.a["title"]         date = item.span.text         yield title, link, date

通过 getContent 函数,获取某一篇文章的正文内容。(如果没有获取到正文部分,则返回 “爬取失败”)

def getContent(html):              bsobj = BeautifulSoup(html,'html.parser')     cnt = bsobj.find('div', attrs={"id":"xw_box"}).find_all("p")     s = ""     if cnt:         for item in cnt:             s += item.text         return s     return "爬取失败!"

通过 saveFile 函数,可以将爬取到的数据保存在本地的 txt 文档里。

def saveFile(path, filename, content):     if not os.path.exists(path):         os.makedirs(path)              # 保存文件     with open(path + filename + ".txt", 'w', encoding='utf-8') as f:         f.write(content)

最后是主函数。

if "__main__" == __name__:      for url in getPageUrl():         s =fetchUrl(url)         for title,link,date in getTitleUrl(s):             print(title,link)             #如果日期在1月21日之前,则直接退出             mon = int(date.split("-")[1])             day = int(date.split("-")[2])             if mon 


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有