爬取新冠疫情数据412状态码解决

解决实时爬取新冠疫情新闻遇到的412状态码以及爬取内容为空的问题

问题出现

最近同学做了一个自动实时爬取新型冠状病毒新闻,并将其转发到邮箱的小程序,在爬取国家卫生应急办公室网站时出现了412状态码问题,之前我也没有认真学习过http状态码,只知道一些很常见的状态码,于是决定认真研究一下。

问题探索

412状态码

翻看RFC官方文档,其对412状态码的概括如下

The 412 (Precondition Failed) status code indicates that one or more conditions given in the request header fields evaluated to false when tested on the server. This response code allows the client to place preconditions on the current resource state (its current representations and metadata) and, thus, prevent the request method from being applied if the target resource is in an unexpected state.

这是一种先决条件失败,即对于目标资源的访问请求被拒绝。一般是由于网页设置了先决条件,这些字段在服务器测试后被认为是“false”从而导致的错误。

selenium绕开412

一般来说,这种问题只会出现在对服务器的POST请求中,在GET请求中很少发生。我观察了很久的头部请求信息也没能找到修改的头绪,可能是因为国家卫生应急办公室增加了一些反爬虫机制,使得在使用各种爬虫库时部分字段被认定为”false”。

这种情况下,直接用爬虫库硬怼可能会很麻烦,由于直接使用浏览器访问网站时不需要任何认证,且网页完全正常,于是决定先使用selenium库模拟浏览器行为进行爬取来绕开412状态码,之后再考虑如何修改头部信息。

selenium使用时略微有一些麻烦,需要安装对应的浏览器驱动,Chrome和Firefox的驱动下载地址分别如下:
Chrome驱动
FireFox驱动

在本地测试时,我下载的Chrome驱动出现了乱码,可能是版本不太兼容的问题,我最终还是选用了FireFox驱动。

使用过程中,直接读取网页源码会出现乱码,爬取内容为空。

我对前端的知识理解还很欠缺,在询问ringotc大佬后,似乎是需要加一个跳转等待,需要从一个临时页面跳转回来,最终完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python
# coding=utf-8
import datetime
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
import selenium.webdriver.support.ui as ui

browser = webdriver.Firefox()

def is_visible(locator, timeout = 10):
try:
ui.WebDriverWait(browser, timeout).until(EC.visibility_of_element_located((By.XPATH, locator)))
return True
except TimeoutException:
return False

browser.get("http://www.nhc.gov.cn/yjb/s7860/202003/816e6f71236b4dca96378df5f6f4ae53.shtml")
#browser.get("http://www.nhc.gov.cn/yjb/pqt/new_list.shtml")
is_visible('/html/body/div[2]/div[2]/div[1]')
html = browser.page_source
content = BeautifulSoup(html, "lxml")

print(content)

这样可以成功获取到页面源码了,根据源码再加一些正则表达式就可以完整地提取出每天的疫情有关新闻了。

总结

本次爬取页面虽然最终达到了目的,即获取国家应急办公室每天的实时新闻,但是并没有解决412状态码的问题,而是用selenium模拟浏览器行为绕开了这一问题。这可能是国家应急办公室网站为了防止恶意爬虫在头部信息中添加了认证信息,使得各种爬虫库均失效,之后有时间的话我也会继续研究412状态码背后的原因,以及是否能用爬虫库直接绕过这一问题。

文章目录
  1. 1. 问题出现
  2. 2. 问题探索
    1. 2.1. 412状态码
    2. 2.2. selenium绕开412
  3. 3. 总结