python爬虫:使用urllib.request和BeautifulSoup抓取新浪新闻标题、链接和主要内容

案例一

抓取对象:

新浪国内新闻(http://news.sina.com.cn/china/),该列表中的标题名称、时间、链接。

完整代码:

  1. from bs4 import BeautifulSoup
  2. import requests
  3. url = ‘http://news.sina.com.cn/china/‘
  4. web_data = requests.get(url)
  5. web_data.encoding = ‘utf-8‘
  6. soup = BeautifulSoup(web_data.text,‘lxml‘)
  7. for news in soup.select(‘.news-item‘):
  8. if(len(news.select(‘h2‘)) > 0):
  9. h2 = news.select(‘h2‘)[0].text
  10. time = news.select(‘.time‘)[0].text
  11. a = news.select(‘a‘)[0][‘href‘]
  12. print(h2,time,a)

运行结果:(只展示部分)

详细解说:

1. 首先插入需要用到的库:BeautifulSoup、requests,然后解析网页。解析完后print下,确认是否解析正确。

  1. from bs4 import BeautifulSoup
  2. import requests
  3. url = ‘http://news.sina.com.cn/china/‘
  4. web_data = requests.get(url)
  5. soup = BeautifulSoup(web_data.text,‘lxml‘)
  6. print(soup)

这时,我们可以看到,解析出来的网页里面有很多乱码,并没有正确解析。观察下结果,看到开头的这句:

<meta content="text/html; charset=utf-8" http-equiv="Content-type"/>

【charset=utf-8】表示当前内容的字符集是采用utf-8编码格式,所以我们需要用encoding来解锁下,这时就能解析出来正常内容。

  1. from bs4 import BeautifulSoup
  2. import requests
  3. url = ‘http://news.sina.com.cn/china/‘
  4. web_data = requests.get(url)
  5. web_data.encoding = ‘utf-8‘
  6. soup = BeautifulSoup(web_data.text,‘lxml‘)
  7. print(soup)

2. 解析出网页后,开始抓取我们需要的内容。首先,先补充几点知识。

看下面代码中的第一行,soup.select(‘.news-item‘),取出含有特定CSS属性的元素时,比如:

  • 找出所有class为news-item的元素,class名前面需要加点(.),即英文状态下的句号;
  • 找出所有id为artibodyTitle的元素,id名前面需要加井号(#)。

另外,取得含有特定标签的HTML元素时,直接在select后写标签名即可,如下面for循环中的第3行,news.select(‘h2‘)。

  1. for news in soup.select(‘.news-item‘):
  2. # print(news)
  3. if(len(news.select(‘h2‘)) > 0):
  4. # print(news.select(‘h2‘)[0].text)
  5. h2 = news.select(‘h2‘)[0].text
  6. time = news.select(‘.time‘)[0].text
  7. a = news.select(‘a‘)[0][‘href‘]
  8. print(h2,time,a)

现在来详细看下这段代码每行的释义。

第1行:soup.select(‘.news-item‘),取出news-item该类中的元素;

第2行:print下news,查看是否被正常解析,正常后继续,不用时可以注释掉;

第3行:通过观察代码,可以看到标题被储存在标签h2中,如果h2的长度大于0,这里是为了去除为空的标题数据;

第4行:print中news.select(‘h2‘)[0].text,[0]是取该列表中的第一个元素,text是取文本数据,print后查看是否正确,不用时可以注释掉;

第5行:将news.select(‘h2‘)[0].text存储在变量h2中;

第6行:time是class类型,前面加点来表示,同上,将其数据存储在变量time中;

第7行:我们要抓取的链接存放在a标签中,链接已经不是text了,后面用href,将链接数据存储在变量a中;

第8行:最后输出我们想要抓取的数据,标题、时间、链接。

案例二

抓取对象:

抓取新闻详情页的标题、时间(进行格式转换)、新闻来源、新闻详情、责任编辑、评论数量和新闻ID。

示例新闻:http://news.sina.com.cn/c/nd/2017-05-08/doc-ifyeycfp9368908.shtml

完整代码:

  1. from bs4 import BeautifulSoup
  2. import requests
  3. from datetime import datetime
  4. import json
  5. import re
  6. news_url = ‘http://news.sina.com.cn/c/nd/2017-05-08/doc-ifyeycfp9368908.shtml‘
  7. web_data = requests.get(news_url)
  8. web_data.encoding = ‘utf-8‘
  9. soup = BeautifulSoup(web_data.text,‘lxml‘)
  10. title = soup.select(‘#artibodyTitle‘)[0].text
  11. print(title)
  12. time = soup.select(‘.time-source‘)[0].contents[0].strip()
  13. dt = datetime.strptime(time,‘%Y年%m月%d日%H:%M‘)
  14. print(dt)
  15. source = soup.select(‘.time-source span span a‘)[0].text
  16. print(source)
  17. print(‘\n‘.join([p.text.strip() for p in soup.select(‘#artibody p‘)[:-1]]))
  18. editor = soup.select(‘.article-editor‘)[0].text.lstrip(‘责任编辑:‘)
  19. print(editor)
  20. comments = requests.get(‘http://comment5.news.sina.com.cn/page/info?version=1&format=js&channel=gn&newsid=comos-fyeycfp9368908&group=&compress=0&ie=utf-8&oe=utf-8&page=1&page_size=20‘)
  21. comments_total = json.loads(comments.text.strip(‘var data=‘))
  22. print(comments_total[‘result‘][‘count‘][‘total‘])
  23. news_id = re.search(‘doc-i(.+).shtml‘,news_url)
  24. print(news_id.group(1))

运行结果:

国土部:5月到9月实行汛期地质灾害日报告制度

2017-05-08 17:21:00

央视新闻

原标题:国土资源部:地质灾害高发期 实行日报告制度

国土资源部消息,5月份将逐渐进入地质灾害的高发期,防灾减灾形势更加严峻。据中国气象局预计,5月份我国江南大部、华南东部、西北地区大部降水较常年同期偏多,应加强防范极端气象事件诱发的滑坡、泥石流等地质灾害。对此从5月起至9月,国土资源部应急办实行汛期地质灾害日报告制度,各地必须将每天发生的灾情险情及其重大工作部署于当天下午3点前报告国土资源部应急办。

李伟山

4

fyeycfp9368908

详细解说:

1. 首先插入需要用到的库:BeautifulSoup、requests、datetime(时间处理)、json(解码:把json格式字符串解码转换成Python对象)、re(正则表达式),然后解析网页。

先抓取标题:

  1. from bs4 import BeautifulSoup
  2. import requests
  3. from datetime import datetime
  4. import json
  5. import re
  6. url = ‘http://news.sina.com.cn/c/nd/2017-05-08/doc-ifyeycfp9368908.shtml‘
  7. web_data = requests.get(url)
  8. web_data.encoding = ‘utf-8‘
  9. soup = BeautifulSoup(web_data.text,‘lxml‘)
  10. title = soup.select(‘#artibodyTitle‘)[0].text
  11. print(title)

datetime、json、re在后面时间转换和从js中抓取数据时会用到。

我们主要来看下倒数第二行代码:title = soup.select(‘#artibodyTitle‘)[0].text,这里的用法和案例一中一样,id前用井号(#)来表示该类元素的位置,解锁唯一元素用[0],提取文本信息text。

2. 抓取时间,并将原有日期格式转化为标准格式

  1. # time = soup.select(‘.time-source‘)[0]
  2. # print(time)
  3. time = soup.select(‘.time-source‘)[0].contents[0].strip()
  4. dt = datetime.strptime(time,‘%Y年%m月%d日%H:%M‘)
  5. print(dt)

第1行:抓取时间;

第2行:print下时间,这时会发现运行结果中既含有时间,还有新闻的来源,如下:

<span class="time-source" id="navtimeSource">2017年05月08日17:21<span>
<span data-sudaclick="media_name"><a href="http://m.news.cctv.com/2017/05/08/ARTIPEcvpHjWzuGDPWQhn77z170508.shtml" rel="nofollow" target="_blank">央视新闻</a></span></span>
</span>

那么,接下来我们需要想办法将时间和来源分开来,这时需要使用到contents;

第3行:我们先在后面加上.contents,运行下后会看到上面的内容会在列表中分为如下2个元素,此时,我们取的时间为第一个元素,在contents后加[0],最后的.strip()可以去除时间末尾的\t;

[‘2017年05月08日17:21\t\t‘, <span>   
<span data-sudaclick="media_name"><a href="http://m.news.cctv.com/2017/05/08/ARTIPEcvpHjWzuGDPWQhn77z170508.shtml" rel="nofollow" target="_blank">央视新闻</a></span></span>, ‘\n‘]

第4行:用datetime.strptime()来做时间格式化,原有的时间是年月日时分,所以转化时用到年月日时分,其中%Y是四位数的年份表示、%m是月份、%d是月份内的一天、%H是24小时制中的小时、%M是分钟数,并将其存储在变量dt中;

第5行:输出dt,会得到格式化后的时间,比如:2017-05-08 17:21:00。

3. 抓取新闻来源:

之前文章《Python爬虫:爬取人人都是产品经理的数据 》中有提到可以用【Copy selector】来复制粘贴出新闻来源的位置,如下第一行;也可以用本篇文章经常用到的class类的表述方法说明其位置,如下第二行;

  1. # source = soup.select(‘#navtimeSource > span > span > a‘)[0].text
  2. source = soup.select(‘.time-source span span a‘)[0].text
  3. print(source)

4. 抓取新闻详情:

  1. article = []
  2. for p in soup.select(‘#artibody p‘)[:-1]:
  3. article.append(p.text.strip())
  4. # print(article)
  5. print(‘\n‘.join(article))

第1行:article为空列表;

第2行:通过观察代码可以发现,新闻详情存放在p标签中,如果直接输出,能看到最后一栏有责任编辑的信息,如果不想要责任编辑,增加[:-1]可以去除最后一个编辑信息;

第3行:将抓取的数据插入article列表中,.strip()去除空白信息;

第4行:可以先print下看结果是否正确,发现新闻详情的原标题和正文是在一排的,不是很好,注释掉后我们换新的方法;

第5行:join()方法用来将列表中的元素用指定的字符连接生成新的字符串,这里用\n换行来连接列表中的原标题和正文两块内容。

上面这是一种文章连接的方法,当然还有比较简洁的写法。我们将上面的for循环一句拿出来,前面加p.text.strip(),然后整体加中括号,这样就形成了一个列表,然后前面再用join将其连接起来,就用简单的一行代码替代了上面的多行代码。

  1. print(‘\n‘.join([p.text.strip() for p in soup.select(‘#artibody p‘)[:-1]]))

5. 抓取责任编辑:

这里用到的lstrip是去除左侧的内容,括号内‘责任编辑:’是指去除这部分内容,只保留编辑人员姓名。之前用到的strip是去除两侧,lstrip是去除左侧,后面会用到的rstrip是去除右侧内容。

  1. editor = soup.select(‘.article-editor‘)[0].text.lstrip(‘责任编辑:‘)
  2. print(editor)

6. 抓取评论数:

  1. # comments = soup.select(‘#commentCount1‘)
  2. # print(comment)
  3. comments = requests.get(‘http://comment5.news.sina.com.cn/page/info?version=1&format=js&channel=gn&newsid=comos-fyeycfp9368908&group=&compress=0&ie=utf-8&oe=utf-8&page=1&page_size=20‘)
  4. # print(comments.text)
  5. comments_total = json.loads(comments.text.strip(‘var data=‘))
  6. # print(comments_total)
  7. print(comments_total[‘result‘][‘count‘][‘total‘])

首先,我们先select(‘#commentCount1‘)来筛选出评论数,这时print下输出结果为[<span id="commentCount1"></span>],span中间为空白信息,没有我们想要的评论数。

这时,我们需要重新去观察下网页代码,发现评论数可能是通过JavaScript来增加上去的,那么我们需要找到是从哪里调用JavaScript(即JS)的。

鼠标放在评论数(4)上,Google浏览器鼠标右键点击“检查”,选择顶部的network,然后在下面海量的链接里找到有数量4的链接。

复制该链接,中间加粗部分是newid,最后有一段像时间戳的字串“&jsvar=loader_1494295822737_91802706”,我们需要把这块内容去掉,然后试着print下,可以发现结果也不会有影响。

http://comment5.news.sina.com.cn/page/info?version=1&format=js&channel=gn&newsid=comos-fyeycfp9368908&group=&compress=0&ie=utf-8&oe=utf-8&page=1&page_size=20&jsvar=loader_1494295822737_91802706

处理好链接后,那么,我们该如何从JavaScript中读取数据呢?这时我们需要使用到json来处理,在开头,我们导入库的时候已经import json了,这里可以直接使用。

json.loads是用于解码json数据的。第5行,我们将解码后的数据存储在变量comments_total中;第6行,我们print该变量时,会得到结果,发现除了评论数之外,还有一些其他的信息。

所以我们需要重新输出,根据上一行print的结果,观察发现,最后一行我们可以用[‘result‘][‘count‘][‘total‘]来表示评论数的位置。

7. 抓取新闻ID:

  1. print(news_url.split(‘/‘)[-1].rstrip(‘.shtml‘).lstrip(‘doc-i‘))

刚在上面第6点抓取评论数时,我们发现链接中有一个newsid,该新闻页面的链接中也有相同的ID部分,这时我们可以明确其新闻ID的位置。

split()是通过指定分隔符对字符串进行切片,[-1]是截取最后一个元素,然后用rstrip去除掉末尾的.shtml,用lstrip去除掉左侧的doc-i,得到我们想要的新闻ID。

除了这种方法外,我们还可以用正则表达式来表达。这时我们需要用到re库,在开头时,我们已经事先import re了,这里直接使用。

其中re.search是扫描整个字符串并返回第一个成功的匹配,group()是匹配到的字符串,其中group(0),是匹配到的字符串全部显示(doc-ifyeycfp9368908.shtml),group(1)是(.+)内的显示,即我们想要的新闻ID。

    1. news_id = re.search(‘doc-i(.+).shtml‘,news_url)
    2. # print(news_id.group(0))
    3. print(news_id.group(1))
时间: 2024-10-03 16:22:52

python爬虫:使用urllib.request和BeautifulSoup抓取新浪新闻标题、链接和主要内容的相关文章

Node.js抓取新浪新闻标题

"use strict"; let cheerio = require("cheerio"); let http = require("http"); let iconv = require("iconv-lite"); let mainUrl = "http://news.sina.com.cn/world/"; http.get(mainUrl, function(sres) { var chunks

python爬虫:抓取新浪新闻内容(从当前时间到之前某个时间段),并用jieba分词,用于训练自己的分词模型

新浪新闻内容采用的是ajax动态显示内容,通过抓包,发现如下规律: 每次请求下一页,js那一栏都会出现新的url: "http://api.roll.news.sina.com.cn/zt_list?channel=news&cat_1=gnxw&cat_2==gdxw1" "||=gatxw||=zs-pl||=mtjj&level==1||=2&show_ext=1&show_all=1&show_num=22&ta

Python抓取新浪新闻数据(二)

以下是抓取的完整代码(抓取了网页的title,newssource,dt,article,editor,comments)举例: 原文地址:http://blog.51cto.com/2290153/2126861

抓取新浪新闻的内容以及链接

import requestsfrom bs4 import BeautifulSoupres = requests.get('http://news.sina.com.cn/china/')res.encoding='utf-8'soup = BeautifulSoup(res.text,'html.parser') for news in soup.select('.news-item'): if(len(news.select('h2'))>0): h2=news.select('h2')

使用fastjson解析json抓取新浪新闻文章

首先看看2个简单的fastjson的使用 例子一 package ivyy.taobao.com.domain.json; import java.util.Iterator; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; /** * @Author:jilongliang * @Date:2014-12-19 * @Version:1.0 * @Description: */ pub

python爬虫----(6. scrapy框架,抓取亚马逊数据)

利用xpath()分析抓取数据还是比较简单的,只是网址的跳转和递归等比较麻烦.耽误了好久,还是豆瓣好呀,URL那么的规范.唉,亚马逊URL乱七八糟的.... 可能对url理解还不够. amazon ├── amazon │   ├── __init__.py │   ├── __init__.pyc │   ├── items.py │   ├── items.pyc │   ├── msic │   │   ├── __init__.py │   │   └── pad_urls.py │  

Python爬虫工程师必学——App数据抓取实战

Python爬虫工程师必学 App数据抓取实战 爬虫分为几大方向,WEB网页数据抓取.APP数据抓取.软件系统数据抓取.主要讲解如何用python实现App数据抓取 数据去重又称重复数据删除,是指在一个数字文件集合中,找出重复的数据并将其删除,只保存唯一的数据单元.数据去重可以有效避免资源的浪费,所以数据去重至关重要 数据去重 数据去重可以从两个节点入手:一个是URL去重.即直接筛选掉重复的URL:另一个是数据库去重.即利用数据库的一些特性筛选重复的数据. def process_spider_

Python 爬虫工程师必学 App数据抓取实战

第1章 课程介绍介绍课程目标.通过课程能学习到的内容.学会这些技能能做什么,对公司业务有哪些帮助,对个人有哪些帮助.介绍目前app数据抓取有哪些困难,面临的挑战,本实战课程会利用哪些工具来解决这些问题,以及本实战课程的特点 ... 1-1 python爬虫工程师必备技能--App数据抓取实战课程导学第2章 windows下搭建开发环境介绍项目开发需要安装的开发软件,讲解了安卓模拟器对比以及夜神安卓模拟器安装.介绍.简单使用和Genymotion安卓模拟器简单分析 介绍App应用抓包工具对比以及f

用Selenium抓取新浪天气

(1)用Selenium抓取新浪天气 系统环境: 操作系统:macOS 10.13.6 python :2.7.10 用虚拟环境实现 一.创建虚拟环境: mkvirtualenv --python=/usr/bin/python python_2 二.激活虚拟环境: workon python_2 三.安装Selenium pip install Selenium 四.安装firefox的Selenium补丁文件: brew install geckodriver 五.在~/.bash_prof