1.设计一个网页爬虫程序或者配置运行开源的网络爬虫进行网页抓取,可以选择爬取新闻网站和电子商务网站的产品评论。不同主题类别的网页存放在不同的目录下
2.掌握网页的标签结构特点以及内容提取原理,设计和实现网页内容提取程序文档内容提取分为2个小题目,任选一个做。
a.提取新闻网页的标题,正文,发表时间。
b.提取某产品的每条产品评论内容,发表时间。
实验环境:Python3.6.2,
IDE:Pycharm 2019.1.3
requests 库主要用来发起网络请求,并接收服务器返回的数据;bs4 库主要用来解析 html 内容,是一个非常简单好用的库;os 库主要用于将数据输出存储到本地文件中。
fetchUrl 函数用于发起网络请求,它可以访问目标 url ,获取目标网页的 html 内容并返回。
这里其实是应该做异常捕获的(我为了简单就省掉了,吐舌头)。因为网络情况比较复杂,可能会因为各种各样的原因而访问失败, r.raise_for_status() 这句代码其实就是在判断是否访问成功的,如果访问失败,返回的状态码不是 200 ,执行到这里时会直接抛出相应的异常。
getPageList 函数,用于爬取当天报纸的各版面的链接,将其保存为一个数组,并返回。
getPageList 函数,用于爬取当天报纸的某一版面的所有文章的链接,将其保存为一个数组,并返回。
getContent 函数,用于访问文章内容页,爬取文章的标题和正文,并返回。
saveFile 函数用于将文章内容保存到本地的指定文件夹中。
download_rmrb 函数是需求中要求的主函数,可以根据 year,month,day 参数,下载该天的全部报纸文章内容,并按照规则保存在指定的路径 destdir 下。
人民日报网站的 URL 的结构还是比较直观的,基本上什么重要的参数,比如日期,版面号,文章编号什么的,都在 URL 中有所体现,构成的规则也很简单,像这样
版面目录:http://paper.people.com.cn/rmrb/html/2019-05/06/nbs.D110000renmrb_01.htm
文章内容:http://paper.people.com.cn/rmrb/html/2019-05/06/nw.D110000renmrb_20190506_5-01.htm
在版面目录的链接中,"/2019-05/06/" 表示日期,后面的 “_01” 表示这是第一版面的链接。
在文章内容的链接中,"/2019-05/06/" 表示日期,后面的 “_20190506_5_01” 表示这是 2019 年 5 月 6 日报纸的第 1 版第 5 篇文章
值得注意的是,在日期的 “月” 和 “日” 以及 “版面号” 的数字,若小于 10,需在前面补 “0” ,而文章的篇号则不必。
了解到这个之后,我们可以按照这个规则,构造出任意一天报纸中人一个版面的链接,以及任意一篇文章的链接。
如:2018 年 6 月 5 日第 4 版的目录链接为:
http://paper.people.com.cn/rmrb/html/2019-05/06/nbs.D110000renmrb_01.htm
2018 年 6 月 1 日第 2 版第 3 篇文章的链接为:
http://paper.people.com.cn/rmrb/html/2018-06/01/nw.D110000renmrb_20180601_3-02.htm
点击访问,发现果然是这样。至此,网站的 URL 组成结构分析完成。
在 URL 分析中,我们也发现了,网站的页面跳转是通过 URL 的改变完成的,不涉及到诸如 Ajax 这样的动态加载方法。也就是说,它的所有数据是一开始就加载好的,我们只需要去 html 中提取相应得数据即可。
好了,言归正传,我们来分析一下我们的目标网站。按 F12 召唤出开发者工具(点击图中 1 处的小箭头,然后点击网页中的内容,可以在 html 源码中快速找到相应的位置)。
我们可以知道,版面目录存放在一个 id = “pageList” 的 div 标签下,class = “right_title1” 或 “right_title2” 的 div 标签中,每一个 div 表示一个版面,而版面的链接就在 id = “pageLink” 的 a 标签中。
使用同样的方法,我们可以知道,文章目录存放在一个 id = “titleList” 的 div 标签下的 ul 标签中,其中每一个 li 标签表示一篇文章,而文章的链接就在 li 标签下的 a 标签中。
进入文章内容页面之后,我们可以知道,文章标题存放在 h1 ,h2 ,h3 标签中(有的文章标题只用到了 h1 标签,而有的文章有副标题可能会用到 h2 或 h3 标签), 正文部分存放在 id = “ozoom” 的 div 标签下的 p 标签里。
至此,目标网站的 HTML 页面分析完成。
通过分析 URL 组成结构以及目标网站的 HTML 结构,我们已经完成了爬虫的前期调研工作,接下来需要根据网站的特点制定相应的爬取策略,然后评估每种方法的优劣和难易程度,最终选择一种最佳方案,进行编码实现。
第一遍,先爬取版面目录,将每一个版面的链接保存下来;第二遍,依次访问每一个版面的链接,将该版面的文章链接保存下来;第三遍,依次访问每一个文章链接,将文章的标题和正文保存到本地。
import requests
import bs4
import os
#URL
def fetchUrl(url):
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',
}
r = requests.get(url,headers=headers)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
#
def getPageList(year, month, day):
url = 'http://paper.people.com.cn/rmrb/html/' + year + '-' + month + '/' + day + '/nbs.D110000renmrb_01.htm'
html = fetchUrl(url)
bsobj = bs4.BeautifulSoup(html,'html.parser')
pageList = bsobj.find('div', attrs = {'id': 'pageList'}).ul.find_all('div', attrs = {'class': 'right_title-name'})
linkList = []
for page in pageList:
link = page.a["href"]
url = 'http://paper.people.com.cn/rmrb/html/' + year + '-' + month + '/' + day + '/' + link
linkList.append(url)
return linkList
#
def getTitleList(year, month, day, pageUrl):
html = fetchUrl(pageUrl)
bsobj = bs4.BeautifulSoup(html,'html.parser')
titleList = bsobj.find('div', attrs = {'id': 'titleList'}).ul.find_all('li')
linkList = []
for title in titleList:
tempList = title.find_all('a')
for temp in tempList:
link = temp["href"]
if 'nw.D110000renmrb' in link:
url = 'http://paper.people.com.cn/rmrb/html/' + year + '-' + month + '/' + day + '/' + link
linkList.append(url)
return linkList
#
def getContent(html):
bsobj = bs4.BeautifulSoup(html,'html.parser')
title = bsobj.h3.text + '\n' + bsobj.h1.text + '\n' + bsobj.h2.text + '\n'
#print(title)
pList = bsobj.find('div', attrs = {'id': 'ozoom'}).find_all('p')
content = ''
for p in pList:
content += p.text + '\n'
#print(content)
resp = title + content
return resp
#本地
def saveFile(content, path, filename):
# 如果没有该文件夹,则自动生成
if not os.path.exists(path):
os.makedirs(path)
# 保存文件
with open(path + filename, 'w', encoding='utf-8') as f:
f.write(content)
#主函数
def download_rmrb(year, month, day, destdir):
pageList = getPageList(year, month, day)
for page in pageList:
titleList = getTitleList(year, month, day, page)
for url in titleList:
# 获取新闻文章内容
html = fetchUrl(url)
content = getContent(html)
# 生成保存的文件路径及文件名
temp = url.split('_')[2].split('.')[0].split('-')
pageNo = temp[1]
titleNo = temp[0] if int(temp[0]) >= 10 else '0' + temp[0]
path = destdir + '/' + year + month + day + '/'
fileName = year + month + day + '-' + pageNo + '-' + titleNo + '.txt'
# 保存文件
saveFile(content, path, fileName)
#入口
if __name__ == '__main__':
year = "2019"
month = "06"
day = "04"
destdir = "C:/data"
download_rmrb(year, month, day, destdir)
print("爬取完成:" + year + month + day)