Python爬虫 - 抓取央视网新闻要闻-新手向(第一篇)

前言

央视网新闻 网站为例,详细讲一下怎么写爬虫,会涉及到一些HTML知识

至于爬虫、HTML是什么我就不废话了,你如果就连这都不知道就不会看了
我这里用的是 Python 来爬,原因就是第三方库多、好用,不用那么费劲找/造 轮子

配置详情:

  • python 3.7
  • requests (网络请求)
  • BeautifulSoup (解析)

首先打开 央视网新闻 进入首页,我们需要获取的是 要闻 要闻

不过我在最下面看到了 点击查看更多内容 的一个链接,这个先不管,只要先知道有就行了;既然要获取要闻的内容,那我们就得获取要闻的源网页内容了,按下键盘上的 F12 打开开发者工具,或者将鼠标放在网页上右键然后点击开发者工具也是一样的,如果你是 Android 手机上的 Chrome 或者 Firefox,你只需要在你这个网页链接前面加上 view-source 就行了,因为手机上的浏览器没有开发者工具,所以就直接查看源代码(PC上的浏览器也可以在链接前面加 view-source 查看源代码)

刚打开肯定是这样的
开发者工具
点一下左上角的那个有着类似 鼠标 图标按钮

接着把鼠标移动到网页里,这时候Element项里会锁定到你鼠标经过的每一个element,element单词意思为元素,也就是 “h1 title html body div” 叫做标签的这些东西
element select
随便点一条要闻,看看在html里是什么,比如这样

我点的是这篇要闻的标题,可以看到在 Element 里出现在 a 标签里,a标签是html里的超链接,不懂看这什么是超链接

每个网站如果它显示了很多条内容,比如这个新闻网站里,它要显示很多条新闻,所以它每一条新闻。。。。你可以把这个每一条新闻想象成一块东西,新闻网里有很多很多块,其实内部都一样(我他妈在说什么…

看向这里

是不是觉得和我上面说的很多很多块一样,有多少新闻内容就有多少这样的div标签,它们的class都是一样的,目的就是为了能很方面的控制这些内容,我们只需要把这些div都扒下来然后慢慢解析出每条新闻的 标题、内容、详细链接 就行了,好吧,打开你的编辑器,开始写代码

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
28
29
30
31
32
33
34
35
36
37
38
39
import requests # 网络请求用到的
from bs4 import BeautifulSoup
import sys

url = "http://news.cctv.com/"
# headers 是最基本的反爬虫手段,一般来说只需要加User-Agent就行了,User-Agent是浏览器标识,判断你是不是浏览器的方法
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", # 养成好习惯,在字典里每写完一项就在其后面加逗号,哪怕这是最后一项
}

# 使用 requests 中的 get 方法来达到网络请求
# 其中第一个参数永远都是url,后面的参数需要指定参数名
resp = requests.get(url, headers=headers)
# 判断返回的状态是不是200,200代表请求OK,这些状态码可以在网上自行了解
if resp.status_code != 200:
print("请求失败!")
sys.exit() # 没有请求成功就直接退出

# 接着开始解析
soup = BeautifulSoup(resp.text, 'html.parser') # BeautifulSoup 需要为其指定一个解析器,没有特殊需求html.parser就行了
'''
soup.find_all 这个方法很容易理解,如果我只传入我想要获取的标签
比如soup.find_all('div'),那么它会返回整个HTML里的所有div的集合给你
当然它还有一个参数为了方便我们准确定位到某个标签,那就是attrs,比如我要获取class为continer的div
soup.find_all('div', attrs={'class': 'continer'}) 就行了
'''

# 我为了避免获取到一些不是要闻里的内容就先获取要闻的曾祖父
col_w660 = soup.find('div', attrs={'class': 'col_w660'})
# 接着用它曾祖父获取它爷爷
main = col_w660.find('div', attrs={'class': 'main'})
# 接着用它爷爷获取它爹
mbd = main.find('div', attrs={'class': 'mhd'})
# 接着从它爹那获取它爹的一堆儿子
con02s = mbd.find_all('div', attrs={'class': 'ecoA9805_con02'})
# 接着输出康一康
for con02 in con02s:
print(con02)
print('done') # 运行完了提示一下自己

接着运行,我是在终端里运行的,命令如下

1
➜  python3 test.py

一回车,WTF,真是一顿操作猛如虎,xxxxxx

看看是哪里出了问题,既然什么都没有输出,那么就说明 con02s 是没有内容的,我们看看 “它爹” 里是什么

1
2
mbd = main.find('div', attrs={'class': 'mhd'})
print(mbd) # 打印它爹
1
2
3
4
➜ python3 test.py
<div class="mhd"><span class="mh_title">覕镻</span><span class="moption"><a href="javascript:getNewData()">整数0敡数镻5畹啻啷数</a> <a class="shuaxin" href="javascript:getNewData()"></a></span></div>
done

我他x,这输出的是什么鬼东西,还有乱码;诶,注意,这里的乱码是因为我们获取的网页编码和我们获取到的网页编码不一样导致的,比如源网页为gbk编码的字节流,而我们抓取下后程序直接使用utf-8进行编码并输出到存储文件中,这必然会引起乱码;这里我发现我们抓取的网页的编码为 utf-8,解决办法很简单,需要修改的地方如下

1
2
3
4
5
6
7
8
resp = requests.get(url, headers=headers)

if resp.status_code != 200:
print("请求失败!")
sys.exit()
resp.encoding = 'utf-8' # 添加这一行即可

soup = BeautifulSoup(resp.text, 'html.parser')

再运行看看

1
2
3
4
➜  python3 test.py
<div class="mhd"><span class="mh_title">要闻</span><span class="moption"><a href="javascript:getNewData()">更新0条新闻,点击刷新</a> <a class="shuaxin" href="javascript:getNewData()"></a></span></div>
done

可以看到没有新闻,这是为毛呢,不知道大家知不知道 ajax,全称 Asynchronous Javascript And XML,JavaScript 里的异步请求方法,很多网站在加载数据的时候为了保证网页不刷新的情况下会用到 ajax 技术,用起来也很简单,这里就不装逼了;怎么获取 ajax 请求呢,打开 开发者工具(F12)后,找到 Network 选项,然后刷新网页,你会发现出现了很多条目,那就是页面加载过程中浏览器与服务器之前发送的请求和接受的响应的所有记录
响应

ajax 有个很特殊的请求类型,就是 xhr,你可以在 Network 窗口下看到 XHR 过滤按钮,默认是 all,切换到 XHR 就能看到所有的 ajax 请求了,这里有一个请求

选择那条后可以看到详细请求信息

Headers 是请求头,Preview 是预览返回的内容,Response 是响应的内容,Cookies 是浏览器缓存,Timing 是请求的耗时啥的(我瞎说的;我们只需要看看Response就行了

很明显这是json,如果你觉得这看不懂,或者看着很恶心,那就点 Preview 吧

这样舒服了吧,点开 rollData 项,可以看到里面的内容和网页中的一样

哎,这就很虚浮,回到Headers,看看是怎么请求的,我们要获取这玩意儿

首先看到General,Request Url为请求的url,Request Method为请求方法,Status Code为状态码,Remote Address为远程服务端的主机地址和端口,Referrer Policy为Referer判断策略;
接着看向 Request Headers,这是我们需要的东西,但也不是全部都要,修改之前的代码,算了直接新建一个文件吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import request
import sys

url = "http://news.cctv.com/data/index.json"
headers = {
'User-Agent': 'ozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
}

resp = requests.get(url, headers=headers)
if resp.status_code != 200:
print('请求失败!')
sys.exit()
# 因为我事先知道返回的结果是json格式的,所以直接调用json()方法即可,返回的是字典对象
print(resp.json())

运行

1
2
3
➜  python3 test.py
{'rollData': [{'title': '中共中央政治局召开会议 中共中央总书记习近平主持会议'...
➜  

成功的获取到了我们需要的东西,很长很长一堆,我省略了,接着就开始解析吧,解析的结果我就把它保存到MongoDB,关于MongoDB的安装以及配置你可以百度或者以后我写一篇文章

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 在上面的代码下追加
import pymongo # python 操作 mongodb 的库
client = pymongo.MongoClient('localhost') # 与本地mongodb建立连接
db = client['cctv_news'] #

rollData = resp.json()['rollData']
for data in rollData:
collection = {
'标题': data['title'],
'Desc': data['description'],# 原谅我见识少实在不知道怎么解释这里的description
'发布时间': data['dataTime'],
'原文链接': data['url'],
'标签': data['content'],
}
try:
if db['news'].insert_one(collection):
print('存储到MongoDB成功.', collection)
except Exception:
print('存储到MongoDB失败!')

然后运行

1
2
➜  python3 test.py
存储到MongoDB成功. {'标题': '内蒙古一男子非法雇佣“三非”外国人被查获'...

看看MongoDB里,成功保存

总结

其实爬虫的用途非常非常的多,爬虫就是为了搜集网络上的数据存在的,我还学识尚浅;这篇文章可能是我写过最长的了,也是可笑,我觉得我写得应该还算详细,有些知识点如果不懂可以留言问我