通过python爬取新浪新闻内容

作者: Eric_Hunter | 来源:发表于2018-02-04 16:38 被阅读311次

这里调用python的各个已知模块(我们暂且称之为模块)来爬取新浪国内新闻的各个子网页的新闻内容。

1.介绍request模块和BeautifulSoup4模块
通过request模块,我们可以有效爬取已知网址链接内的网页源代码,但是如果我们需要爬取有效的新闻内容还需要用到BeautifulSoup4模块。

//例1,通过request模块爬取“新浪新闻国内新闻”的源码
import requests

res = requests.get('http://news.sina.com.cn/china/')
res.encoding = 'utf-8'   #通过修改编码方式为utf-8,使得汉字得到识别
print(res.text)
//例2,通过BeautifulSoup4模块来将网页源代码中的有效内容提取出来(请联系下文的soup)
from bs4 import BeautifulSoup
html_sample = ' \
<html> \
    <body> \
    <h1 id="title">Hello World</h1> \
    <a href="#" class="link">This is link1</a> \
    <a href="# link2" class="link">This is link2</a> \
    </body> \
<html>'

#这里的'html.parser'是为了告诉BeautifulSoup这个html_sample的解析形式是html格式#
soup = BeautifulSoup(html_sample, 'html.parser')    print(soup.text)
//输出:Hello World This is link1 This is link2

2.select函数的使用(请联系上文的soup)
2.1找出所有含有特定标签的HTML元素

//例3,使用select找出含有“h1”标签的元素
soup = BeautifulSoup(html_sample, 'html.parser')
header = soup.select('h1')
print(header)
print(header[0])
print(header[0].text)
//输出:[<h1 id="title">Hello World</h1>]
<h1 id="title">Hello World</h1>
Hello World
//例4,使用select找出含有“a”标签的元素(请联系上文的soup)
soup = BeautifulSoup(html_sample, 'html.parser')
alink = soup.select('a')
print(alink)
Print()
for link in alink:
    print(link)
print(link.text)
//输出:[<a class="link" href="#">This is link1</a>, <a class="link" href="# link2">This is link2</a>]

<a class="link" href="#">This is link1</a>
This is link1
<a class="link" href="# link2">This is link2</a>
This is link2

2.2 取得含有特定CSS属性的元素(请联系上文的soup)

//例5,使用select找出所有id为“title的”元素(id前面需加 “#”)  id表示独立而不重复的元素(注:对于class,因为它的元素会有重复,所以在该class的名称前加“.”就Ok,其他都一样)
soup = BeautifulSoup(html_sample, 'html.parser')
header = soup.select('#title')
print(header)
print(header[0].text)
//输出:[<h1 id="title">Hello World</h1>]
Hello World

2.3 取得所有a标签内的链接(请联系上文的soup)

//例6,使用select找出所有 a tag 的 href链接
soup = BeautifulSoup(html_sample, 'html.parser')
alinks = soup.select('a')
for link in alinks:
#href是Hypertext Reference的缩写。意思是指定超链接目标的URL。是css代码的一种。#
    print(link['href'])     
//输出:#
# link2
//例7
a = '<a href="#" qoo=12345 abc=ghjlks>I am a link</a>'
soup2 = BeautifulSoup(a, 'html.parser')
print(soup2.select('a'))
print(soup2.select('a')[0])
print(soup2.select('a')[0]['abc'])
print(soup2.select('a')[0]['href'])
print(soup2.select('a')[0]['qoo'])
print(soup2.select('a')[0].text)
//输出:
[<a abc="ghjlks" href="#" qoo="12345">I am a link</a>]
<a abc="ghjlks" href="#" qoo="12345">I am a link</a>
ghjlks
#
12345
I am a link

3.爬虫正式介绍
3.1 在这里我们要首先要介绍使用chrome浏览器的一个网页解析功能(我们以“http://news.sina.com.cn/china/”为例):
1)在该网页下右击鼠标,点击“检查(N)”,就会进入一个界面如下图1.

图1

2)点击“NetWork”按钮,如图2.


图2

这里显示的是一片空白,于是我们应该在左边网页内容部分点击右键,然后点击“重新加载(R)”

3)页面重新加载后,我们在解析页面的副标题下找到“Doc”并点击进入,如下图3.


图3

在这个页面我们可以看到“Name”标题栏中第一行有个“china/”这个list。

4)点击进入“china/”这个list,然后点击“Response”这一栏,如图4


图4

进入,通过对比浏览我们可知,这部分展示的就是该网页的源代码。

5)点击“Headers”这一栏,如图5

图5
我们可以知道该网页的URL是:<u>http://news.sina.com.cn/china/</u><u>;</u> 网页的请求方式是:GET

3.2 爬取主网页的各个子新闻的标题、时间、网页链接
于是,我们就可以动工开始书写我们的爬虫了。

//例8
import requests
from bs4 import BeautifulSoup

#这里使用requests模块的get函数,因为我们从上可知网页的请求方式是:get#
res = 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')[0].text
        time = news.select('.time')[0].text
        link = news.select('a')[0]['href']
        print(time, '|', h2, '|', link)

由此,我们将“新浪新闻国内新闻”主页面下的各个新闻的发布时间、标题、该标题下的新闻内容网页链接都打印出来了,如图6.


图6

3.3 爬取具体新闻网页的新闻内容
3.3.1我们想要获取新闻的标题
1)进入具体新闻网页(我们这里假设进入:“http://news.sina.com.cn/c/nd/2018-01-30/doc-ifyqzcxi1656480.shtml”),见图7.

图7

2)点击解析功能左上角的箭头按钮(英文名称“Select an element in the page to inspect it”),然后使用鼠标点击标题,在解析功能页面的左半部分会显示出该标题的代码部分,见图8.


图8

我们通过分析,得到这里的标题是个class = “main-title”(所以我们应该使用soup.select(‘.main-title’))

3.3.2我们想要获取新闻的发布时间
我们使用解析功能得到新闻发布时间的代码部分,见图9.


图9

这里我们见到在时间所属的class = “date”(所以我们使用date = soup.select('.date')[0].contents[0])

3.3.3我们想要获取新闻的编辑
我们使用解析功能得到新闻编辑的代码部分,见图10.


图10

这里我们见到在编辑所属的class = “show_author”(所以我们使用editor = soup.select('.show_author')[0].text)

3.3.3 我们想要获取新闻的评论数
我们使用解析功能,但是如果使用类如3.3.1、3.3.2的方式找新闻评论数我们会发现我们可以找到评论数代码的具体位置,但是无法把它展现出来,那我们假设它是用JS或CSS写出来的,于是我们在‘JS’和‘CSS’目录下找寻,于是我们在‘JS’目录下找到如图11.


图11

在‘JS’的‘Preview’下我们看到‘result’,点击进入,见图12.


图12

这就是我们想要得到的评论总数。但是我们还要将评论数输出,于是我们点击‘Headers’,如图13.

图13
得到该评论界面的url, 然后我们将链接复制出来(该链接为:’http://comment5.news.sina.com.cn/page/info?version=1&format=json&channel=gn&newsid=comos-fyqyqni5607627&group=undefined&compress=0&ie=utf-8&oe=utf-8&page=1&page_size=3&t_size=3&h_size=3&thread=1&callback=jsonp_1517486078758&_=1517486078758’),于是我们将其赋给代码段:
import json

com = 'http://comment5.news.sina.com.cn/page/info?version=1&format=json&channel=gn&newsid=comos-fyqyqni5607627&group=undefined&compress=0&ie=utf-8&oe=utf-8&page=1&page_size=3&t_size=3&h_size=3&thread=1&callback=jsonp_1517486078758&_=1517486078758'
res = requests.get(com)
jd = json.loads(res.text)
jd['result']['count']['total']
但是这里执行发生了问题:JSONDecodeError: Expecting value: line 1 column 1 (char 0)
我们发现这里末尾的’=jsonp_1517486078758&_=1517486078758’是引发问题的症结所在,去掉它。
import json

com = 'http://comment5.news.sina.com.cn/page/info?version=1&format=json&channel=gn&newsid=comos-fyqyqni5607627&group=undefined&compress=0&ie=utf-8&oe=utf-8&page=1&page_size=3&t_size=3&h_size=3&thread=1&callback'
res = requests.get(com)
jd = json.loads(res.text)
jd['result']['count']['total']

我们得到正确的总评论数。(关于json函数,详见:‘https://docs.python.org/3/library/json.html’)

3.3.4我们想要获取新闻的正文内容

我们使用解析功能得到新闻正文内容的代码部分,见图14.


图14

�这里我们见到在编辑所属的class = “article”(所以我们使用[p.text.strip() for p in soup.select('.article p'))
(注:这里在soup.select('.article p')加入p是因为在select出article类中的<p>后面的内容)

好,这里我们得到了我们想要的东西,代码汇总为:

//例9,通过已知新闻网页得到文章正文及其他内容
import requests
import json
import re
from bs4 import BeautifulSoup
from datetime import datetime

#我们将评论的页面链接处理成一个带有‘{}’的str,这样通过format就可以在任意页面id的评论页面中获取评论数了#
commentsURL = 'http://comment5.news.sina.com.cn/page/info?version=1&\
format=json&channel=gn&newsid=comos-{}&group=undefined&compress=\
0&ie=utf-8&oe=utf-8&page=1&page_size=3&t_size=3&h_size=3&thread=1&callback'

#我们将获取评论数封装成函数,这样在以后获取就方便了#
def getcomments(newurl):    
    m = re.search('doc-i(.*).shtml', newurl)
    newid = m.group(1)
    comments = requests.get(commentsURL.format(newid))
    jd = json.loads(comments.text)
    num = jd['result']['count']['total']
    return num

def getnewsdetail(newurl):
    result = {}
    article = []
    res = requests.get(newurl)
    res.encoding = 'utf-8'
    soup = BeautifulSoup(res.text, 'html.parser')
    result['title'] = soup.select('.main-title')[0].text
    timesource = soup.select('.date')[0].contents[0]
    result['time'] = timesource
    result['editor'] = soup.select('.show_author')[0].text.strip('责任编辑:')#去除“责任编辑:”
    result['commetntsnum'] = getcomments(newurl)
    article2 = soup.select('.article p')[1:-1]
    for p in article2:
        article.append(p.text.strip())
    result['article'] = article
 
    return result

newurl= 'http://news.sina.com.cn/c/gat/2018-01-30/doc-ifyqyqni5216530.shtml'
getnewsdetail(newurl)

4.通过主页爬出各个子网页的新闻
4.1 获取主网页下的各个子网页链接
这里我们需要借助主页的api接口来获取各个子页面的网址链接
1)我们通过刷新页面,得到网页解析工具中有些NetWork是不改变的,而新闻是在事时更新的,所以我们假设是不是会有一些链接也在事时更新?那是不是有个api接口来负责各个网页区块的更新呢?于是我们找到如下图15的内容。


图15

2)于是我们点击“Headers”,如图16.

图16
得到链接多条子新闻的接口(“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&tag=1&format=json&page=2&callback=newsloadercallback&_=1517489007585”)。

于是我们得到例10.

//例10,获取主网页下的各个子文章链接
import requests
import json

res = requests.get('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&tag=1&format=json&page=\
1&callback=newsloadercallback&_=1517384350209')

#lstrip()为从左起去掉1个括号内的符号(如果有的话),同理,rstrip()是从右起#
jd = json.loads(res.text.lstrip('  newsloadercallback(').rstrip(');'))
l = jd['result']['data']
for i in l:
    print(i['url'])

将其封装成函数:
def parseListLink(url):
    res = requests.get(url)
    jd =  json.loads(res.text.lstrip('  newsloadercallback(').rstrip(');'))
    temp = jd['result']['data']
    arraylinks = []
    for p in temp:
        arraylinks.append(p['url'])
return arraylinks

最后,我们就可以放大招了,将所有的函数整合起来,从而爬取各个子网页的新闻内容。

#通过已知新闻网页得到文章正文及其他内容
import requests
import json
import re           #引入正则表达式
from bs4 import BeautifulSoup
from datetime import datetime

def getcomments(newurl):
    m = re.search('doc-i(.*).shtml', newurl)        #通过正则来获取id
    newid = m.group(1)
    comments = requests.get(commentsURL.format(newid))
    jd = json.loads(comments.text)
    num = jd['result']['count']['total']
    return num

def getnewsdetail(newurl):
    result = {}
    article = []
    res = requests.get(newurl)
    res.encoding = 'utf-8'
    soup = BeautifulSoup(res.text, 'html.parser')
    result['title'] = soup.select('.main-title')[0].text
    timesource = soup.select('.date')[0].contents[0]#soup.select('.date-source span')[0].text
    result['time'] = timesource
    result['editor'] = soup.select('.show_author')[0].text.strip('责任编辑:')
    result['commetntsnum'] = getcomments(newurl)
    article2 = soup.select('.article p')[1:-1]
    for p in article2:
        article.append(p.text.strip())
    result['article'] = article
    #all = {'title':title, 'time':time, 'editor':editor, 'num':num, 'article':article}
    return result

#获取主网页下的各个子文章链接函数形式

def parseListLink(url):
    res = requests.get(url)
    jd =  json.loads(res.text.lstrip('  newsloadercallback(').rstrip(');'))
    temp = jd['result']['data']
    arrylinks = []
    for p in temp:
        arrylinks.append(p['url'])
    return arrylinks


commentsURL = 'http://comment5.news.sina.com.cn/page/info?version=1&\
format=json&channel=gn&newsid=comos-{}&group=undefined&compress=\
0&ie=utf-8&oe=utf-8&page=1&page_size=3&t_size=3&h_size=3&thread=1&callback'

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&tag=1&format=json&page=\
{}&callback=newsloadercallback&_=1517384350209'

news_total = []
news_detail = []
for i in range(1,2):
    news_total.extend(parseListLink(url.format(i)))
#print(news_total)
print(len(news_total))
for j in news_total:
    news_detail.append(getnewsdetail(j))
print(news_detail)

好了,我们获取了那么多新闻,是不是应该把它们存储起来呢?于是我们可以用“pandas”这个模块。

import pandas

#将news_detail 中的每一条数据存到df中去#
df = pandas.DataFrame(news_detail)
#将df的内容存到根目录下的“news.xlsx”文件中#
df.to_excel('news.xlsx')    

相关文章

  • 通过python爬取新浪新闻内容

    这里调用python的各个已知模块(我们暂且称之为模块)来爬取新浪国内新闻的各个子网页的新闻内容。 1.介绍req...

  • python爬虫

    一、新闻爬虫实战(爬取新浪新闻首页所有新闻内容)思路:1、爬取新闻首页2、得到各新闻链接3、爬取新闻链接4、寻找有...

  • Python爬虫入门-爬取新浪新闻

    运行环境:Python3.6.0 所需的包: 爬取结果:

  • 新浪新闻爬取(selenium)

    github链接:spider/README.md at master · azirff/spider · GitHub

  • Python 实战项目

    web机器人 web实战 博客BBS论坛系统 成绩管理系统 新闻系统 爬取知乎 爬取豆瓣 爬取京东 爬取新浪微博 ...

  • 行业垂直搜索引擎的构建

    1 项目的功能 爬取新闻(爬取网站可配置,精准爬取需要内容); 抽取新闻内容,存入数据库(精准抽取); 建立索引(...

  • 各类链接

    爬虫 使用python-aiohttp爬取今日头条 【Python】爬虫爬取各大网站新闻 Scrapy 模拟登录新...

  • 30行Python代码,抓取全网实时热点,获取最新资讯

    想要获取最新实时新闻资讯吗?Python带实现全网爬取新浪新闻重要的头条资讯,你只要运行一下代码,就能快捷地获取新...

  • python 爬取搜狐新闻

    python2.7,通过urllib2和BeautifulSoup爬取新闻 文中还包括一些BeautifulSou...

  • python-新浪爬取话题微博实践

    说完模拟登录之后呢,现在讲述对于手机端新浪的爬取过程,此例讲述针对Ajax异步请求内容的爬取,以新浪微博“小黄车”...

网友评论

本文标题:通过python爬取新浪新闻内容

本文链接:https://www.haomeiwen.com/subject/sswmzxtx.html