Python 网络爬虫实战(爬取南方周末新闻文章(带关键词筛选))

弓背霞明剑照霜,秋风走马出咸阳。这篇文章主要讲述Python 网络爬虫实战:爬取南方周末新闻文章(带关键词筛选)相关的知识,希望能为你提供帮助。

1. 分析网站南方周末,网站地址为:http://www.infzm.com/contents?term_id=1

Python 网络爬虫实战(爬取南方周末新闻文章(带关键词筛选))

文章图片

观察网站主页,我们可以了解到,网站左侧为 ??频道列表?? ,中间为 ??新闻列表?? 。
鼠标点击切换左侧的频道时,观察到浏览器地址栏中 ??term_id?? 的值同步发生变化,说明 ??term_id?? 参数表示频道的 ??id?? 。
将网页滚动条往下滑,观察到会不断有新的新闻文章加载进来,但是浏览器地址栏中的网址全程没有变化,说明新闻列表采用 ??瀑布流?? 的加载形式,数据通过 ??Ajax?? 动态加载。
简单分析之后,我们打开 ??开发者工具?? ,切换到 ??Network?? 页签开始抓包分析。
1.1 新闻列表分析
Python 网络爬虫实战(爬取南方周末新闻文章(带关键词筛选))

文章图片

在页面下滑的过程中,不断有新的请求出现。
请求的 URL 形如: http://www.infzm.com/contents?term_id=1& page=2& format=json
【Python 网络爬虫实战(爬取南方周末新闻文章(带关键词筛选))】请求的内容如图所示:
Python 网络爬虫实战(爬取南方周末新闻文章(带关键词筛选))

文章图片

到这里我们知道了,这个便是我们要找的 ??新闻列表?? 的数据接口。
观察接口 URL:http://www.infzm.com/contents?term_id=1& page=2& format=json
有 3 个参数:??term_id?? ,??page?? 和 ??format?? 。
??term_id?? 前面分析过了表示频道的 id,其他两个根据字面含义,??page?? 表示页数,??format?? 表示数据格式。
返回的数据格式是标准的 ??json?? ,文章列表数据位于 ??data -> contents?? ,包括文章标题,文章id,作者名字,发布时间等信息。
1.2 新闻详情页分析随便打开一篇新闻文章的详情页,如:http://www.infzm.com/contents/217973 。
我们观察到详情页链接的构成方式为 ??http://www.infzm.com/contents/?? + ??文章id?? 。
通过开发者工具查看,了解到新闻正文内容渲染在 ??html?? 源码中。
Python 网络爬虫实战(爬取南方周末新闻文章(带关键词筛选))

文章图片

如图所示,新闻内容在 ??< div class="nfzm-content__content"> ?? 标签中。其中 ??引言?? 部分位于 ??< blockquote class="nfzm-bq"> ?? 标签下;正文内容位于 ??< div class="nfzm-content__fulltext"> ?? 标签下的 ??p?? 标签中。
网页结构示意如下:

< div class="nfzm-content__content">
< blockquote class="nfzm-bq"> 引言< /blockquote>
< div class="nfzm-content__fulltext">
< p> 第一段< /p>
< p> 第二段< /p>
< p> 第三段< /p>
< /div>
< /div>


1.3 反爬机制分析我们用 python 简单编写一段代码,测试一下网站的反爬机制。
1.3.1 新闻列表
简单伪造一下 headers ,发起网络请求。

import requests

headers = {
accept: text/html,application/xhtml+xml,application/xml; q=0.9,image/webp,image/apng,*/*; q=0.8,
user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36,
}
url = "http://www.infzm.com/contents?term_id=1& page=2& format=json"
r = requests.get(url, headers=headers)
r.encoding = r.apparent_encoding
print(r.text)


发现可以正常获取到数据。
Python 网络爬虫实战(爬取南方周末新闻文章(带关键词筛选))

文章图片

1.3.2 新闻正文

import requests

headers = {
accept: text/html,application/xhtml+xml,application/xml; q=0.9,image/webp,image/apng,*/*; q=0.8,
user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36,
}
url = "http://www.infzm.com/contents/217973"
r = requests.get(url, headers=headers)
r.encoding = r.apparent_encoding
print(r.text)


新闻正文内容也可以成功获取到。
Python 网络爬虫实战(爬取南方周末新闻文章(带关键词筛选))

文章图片

不过并不是所有新闻正文都可以无障碍爬取到,有些新闻正文仅展示部分内容,全文需要登录账号之后才能查看。
Python 网络爬虫实战(爬取南方周末新闻文章(带关键词筛选))

文章图片

而当我注册好账号之后刷新界面,发现查看全文居然还要订阅会员。
Python 网络爬虫实战(爬取南方周末新闻文章(带关键词筛选))

文章图片

这里我就先不开通会员了。
如果有需要的同学,可以自行开通会员后,将登录后的 ??cookies?? 填入代码中的 ??headers?? 中,进行爬取。

headers = {
accept: text/html,application/xhtml+xml,application/xml; q=0.9,image/webp,image/apng,*/*; q=0.8,
user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36,
Cookie: "你自己的cookie"
}


Cookie 可以在开发者工具中查看。
2. 编码环节接下来,开始正式编码。
首先导入这个爬虫程序需要用到的库

import requests
import json
from bs4 import BeautifulSoup
import os


然后是网络请求函数 ??fetchUrl??

def fetchUrl(url):

功能:访问 url 的网页,获取网页内容并返回
参数:目标网页的 url
返回:目标网页的 html 内容

headers = {
accept: text/html,application/xhtml+xml,application/xml; q=0.9,image/webp,image/apng,*/*; q=0.8,
user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36,
}
try:
r = requests.get(url, headers=headers)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except Exception as e:
print(e)


解析新闻列表函数 ??parseNewsList??

def parseNewsList(html):

功能:解析新闻列表页,提取新闻列表数据并依次返回
参数:列表数据(json 格式)
返回:新闻的id,标题,发布时间

try:
jsObj = json.loads(html)
contents = jsObj["data"]["contents"]
for cnt in contents:
pid = cnt["id"]
subject = cnt["subject"]
publish_time = cnt["publish_time"]
yield pid, subject, publish_time

except Exception as e:
print("parseNewsList error!")
print(e)


解析新闻正文内容函数 ??parseNewsContent??

def parseNewsContent(html):

功能:解析新闻详情页,提取新闻正文内容并返回
参数:网页源码(html 格式)
返回:新闻正文内容的字符串

try:
bsObj = BeautifulSoup(html, "html.parser")
cntDiv = bsObj.find("div", attrs={"class": "nfzm-content__content"})
blockQuote = cntDiv.find("blockquote", attrs={"class": "nfzm-bq"})
fulltextDiv = cntDiv.find("div", attrs={"class": "nfzm-content__fulltext"})
pList = fulltextDiv.find_all("p")

ret = blockQuote.text + "\\n" if blockQuote else ""
ret += "\\n".join([p.text for p in pList if len(p.text) > 1])
return ret

except Exception as e:
print("parseNewsContent error!")
print(e)


保存文件函数 ??saveFile??

def saveFile(path, filename, content):

功能:将文章内容 content 保存到本地文件中
参数:要保存的内容,路径,文件名

# 如果没有该文件夹,则自动生成
if not os.path.exists(path):
os.makedirs(path)
# 保存文件
with open(path + filename, w, encoding=utf-8) as f:
f.write(content)


爬虫调度器 ??download_nfzm??

def download_nfzm(termId, page, savePath):

功能:爬取 termId 频道,第 page 页的所有新闻,并保存至 savePath 路径下
参数:termId 频道 Id
page 页码
savePath 保存路径

url = f"http://www.infzm.com/contents?term_id={termId}& page={page}& format=json"
html = fetchUrl(url)
try:
for

    推荐阅读