频道栏目
首页 > 资讯 > Python > 正文

Python爬取新浪英超曼联文章内页--bs4,json,txt和csv以及编码

17-01-09        来源:[db:作者]  
收藏   我要投稿

这个页面是新浪英超曼联新闻的首页,直接用lxml爬取,得到它是动态的爬不到,所以要考虑它的信息处理机制,使用Chrome审查元素,在Network--Priview中可以找到它的json源。通常可以把&callbacak=直到最后删除,之前的信息似乎没什么用处,有用的时候再说。

之后使用json解析。

必须仔细观察json的结构,而且还需要不断地断点调试。

import requests

import json

headersIm = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}

#network headers里面

url_sport = "http://interface.sina.cn/pc_zt_roll_news_index.d.html?&subjectID=64558&channel=sports"

# json_url = 'http://interface.sina.cn/pc_zt_api/pc_zt_press_news_doc.d.json?subjectID=64558&cat=&size=40&page=1&channel=sports&callback=jsonpcallback1483559621857'

json_url = 'http://interface.sina.cn/pc_zt_api/pc_zt_press_news_doc.d.json?subjectID=64558&cat=&size=40&page=1&channel=sports'

jsContent = requests.get(json_url, headers = headersIm).content

print jsContent

jsDict = json.loads(jsContent)

jsResult = jsDict['result']

jsData = jsResult['data']

for each in jsData:

print each['title']

今天的结果:

穆帅示爱曼联球迷+球队 他终成“快乐的一个”?

7战6球!伊布当选英超月最佳 力压切尔西王牌

曼联大将自晒缝针照片 穆帅手下他已成红魔枢纽

打脸!谁说穆里尼奥会毁了曼联两大妖王?

曝穆帅欲签一昔日爱将 在皇马切尔西都用过他

......

虽然爬取网页信息,爬的不多,但是通常有两大方法:一个是从网页本身入手用lxml定位相应的h5元素,另一个是直接找信息源,通常是json。

又运行了一下程序,得到的结果是:

曼联猎物正式提交转会申请 同胞丰特或驰援鸟叔

曼联宣布12月最佳球员 伊布力压两核心首当选......

证明这个爬虫确实是爬取动态网站的。

没做完的部分:将标题,内容都整理好,只爬取前20条信息就足够了(或者加上后面10页的内容),进入内页后,将文章的文字部分也提取出来。

一、问题:

显然,只爬取标题是不够的,最主要的还是url链接,内页的正文:

foreach injsData:
    print each['title']+" "+each['url']

显然,所有有用的信息都已经在jsData这个列表里面,而现在为止,有两个问题:

1. 下一页的数据如何爬取;

2. 新闻内页的文字如何爬取。

二、分析

首先,下一页的数据。点击底下的页码的时候,数据变化,而浏览器地址栏是不变的,所以还是要从json源的地址入手。而通过观察json源地址:http://interface.sina.cn/pc_zt_api/pc_zt_press_news_doc.d.json?subjectID=64558&cat=&size=40&page=1&channel=sports可知,page=1,这个1很可能是相应页码,同时,共114页,我们只取前20。

for i in range(1, 21):
    print i

所以可以构造一个函数专门来读取标题+日期+正文。

以页面:http://sports.sina.com.cn/g/pl/2017-01-07/doc-ifxzkfuk2454395.shtml为例,可知想得到的信息分别是:

标题:<h1id="artibodyTitle">欧文:穆帅别抱怨裁判专注比赛吧瓜帅没必要改变</h1>

           title_news =bsObj.find("h1",{"id":"artibodyTitle"}).string     #获取h1标签的内容

日期:<spanid="pub_date">2017年01月07日07:01</span>

           date_news =bsObj.find("span", {"id":"pub_date"}).string       #同上

内容:<divclass="BSHARE_POP blkContainerSblkCon clearfixblkContainerSblkCon_14" id="artibody">下的所有p标签的内容。

           content_news =bsObj.find("",{"id":"artibody"}).findAll("p")   #先找到id为artibody的元素,再向下寻找p标签

    for content in content_news:

        print content.get_text()                    #获得每一个p标签的内容

三、构造

至此,这个函数已写完,解析新闻内页的函数:

def getNewsContent(url_news):
    html_WebPage = requests.get(url_news,headers = headersIm)
    html_WebPage.encoding = 'utf-8'
    html_WebText = html_WebPage.text
    bsObj = BeautifulSoup(html_WebText, 'lxml')     #shtml的解析使用lxml方式
    title_news = bsObj.find("h1",{"id":"artibodyTitle"}).string  #获取h1标签的内容
    date_news = bsObj.find("span", {"id": "pub_date"}).string       #同上
    content_news = bsObj.find("", {"id":"artibody"}).findAll("p")   #先找到id为artibody的元素,再向下寻找p标签
    for content in content_news:
        print content.get_text()      #获得每一个p标签的内容

像这种:http://k.sina.cn/article_5695956221_1538164fd02000165x.html?cre=aspect&mod=2L&loc=27&r=0&doct=0&rfunc=39&tj=none&s=0&from=sports&vt=4就不解析了,所以还要用到Python的try...except。另外就是把标题,时间,内容,都存储为csv和txt,后面我分别写。

然而,获得的标题,时间,内容,经过测试,都是NavigableString类型的,需要把这种类型写入txt。只要在这种对象后面加上.encode('utf-8')即可转换:title_news = bsObj.find("h1",{"id":"artibodyTitle"}).string.encode('utf-8')

四、写入txt

最终的程序,把文章标题,日期,和内容存储在txt文档中(爬小说像不像):

# encoding=utf-8 注释可用中文
import requests
import json
from bs4 import BeautifulSoup

headersIm = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
f = open("news.txt", 'a')
def getNewsContent(url_news):
    html_WebPage = requests.get(url_news,headers = headersIm)
    html_WebPage.encoding = 'utf-8'
    html_WebText = html_WebPage.text
    bsObj = BeautifulSoup(html_WebText, 'lxml')     #shtml的解析使用lxml方式
    try:
        title_news = bsObj.find("h1",{"id": "artibodyTitle"}).string.encode('utf-8')     #获取h1标签的内容,.encode('utf-8')转换为str
        date_news = bsObj.find("span", {"id": "pub_date"}).string.encode('utf-8')       #同上
        content_news = bsObj.find("", {"id":"artibody"}).findAll("p")   #先找到id为artibody的元素,再向下寻找p标签
        f.write(title_news.rstrip()+'----'+date_news.lstrip())  #将标题和日期用----连接,并删除标题右侧和日期左侧的空格回车等,规范格式 写入
        for content in content_news:
            news_text = content.get_text().encode('utf-8')                    #获得每一个p标签的内容,转换为str
            f.write(news_text)                    #写入txt
            f.write('\n')            #文章末尾加换行符,区别两块新闻
    except:
        pass
    finally:
        pass

def newsListPages(urlPages):
    jsContent = requests.get(urlPages, headers=headersIm).content   #requsets解析文章列表
    jsDict = json.loads(jsContent)        #将内容用json库解析
    jsResult = jsDict['result'] 
    jsData = jsResult['data']
    for each in jsData:
        newsUrl = each['url']   #获得相应文章的url
        getNewsContent(newsUrl) #函数解析文章内页内容

for i in range(1, 3):
    url_json = 'http://interface.sina.cn/pc_zt_api/pc_zt_press_news_doc.d.json?subjectID=64558&cat=&size=40&page='+str(i)+'&channel=sports'
        #构造json数据源的地址
    newsListPages(url_json)

f.close()

原理:分析从上至下,构建从下至上。首先分析树状结构,之后再构建解析文章—解析文章列表。但是,这样单线程似乎有点慢,如果用多线程的方式,首先需要构建文章列表,再用函数进行统一解析。

结果:

尴尬!鲁尼找对手换球衣被拒 来自曼城的恨(图)----2017年01月08日01:11

新浪体育讯  曼联4-0大胜雷丁一战,对于鲁尼本人意义非凡,此役他追平了队史射手王查尔顿爵士249球的纪录。按理说,这样一场比赛,谁都想沾沾鲁尼的喜气,但是雷丁后卫乔治-埃文斯便是个另类,他拒绝了鲁尼主动交换球衣的请求,原因是什么呢?

五、写入csv

写入csv格式类似:

# encoding=utf-8 注释可用中文
import requests
import json
from bs4 import BeautifulSoup
import csv
import codecs  #保证csv能正确写入的库

headersIm = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
csvfile = file('csv_test.csv', 'wb')    #创建csv文件,并准备写入
csvfile.write(codecs.BOM_UTF8)  #csv写入中文必备
writer = csv.writer(csvfile)    #构建写入对象
writer.writerow(['标题', '日期', '内容'])
def getNewsContent(url_news):
    html_WebPage = requests.get(url_news,headers = headersIm)
    html_WebPage.encoding = 'utf-8'
    html_WebText = html_WebPage.text
    bsObj = BeautifulSoup(html_WebText, 'lxml')     #shtml的解析使用lxml方式
    try:
        title_news = bsObj.find("h1",{"id": "artibodyTitle"}).string.encode('utf-8')     #获取h1标签的内容,.encode('utf-8')转换为str
        date_news = bsObj.find("span", {"id": "pub_date"}).string.encode('utf-8')       #同上
        content_news = bsObj.find("", {"id":"artibody"}).findAll("p")   #先找到id为artibody的元素,再向下寻找p标签
        content_str = ''
        for content in content_news:
            news_text = content.get_text().encode('utf-8')                    #获得每一个p标签的内容,转换为str
            content_str += news_text      #将文章正文存储在相应字符串中
        writer.writerow([title_news, date_news, content_str])   #构建每一行的格式,并写入
    except:
        pass
    finally:
        pass

def newsListPages(urlPages):
    jsContent = requests.get(urlPages, headers=headersIm).content   #requsets解析文章列表
    jsDict = json.loads(jsContent)        #将内容用json库解析
    jsResult = jsDict['result']
    jsData = jsResult['data']
    for each in jsData:
        newsUrl = each['url']   #获得相应文章的url
        getNewsContent(newsUrl) #函数解析文章内页内容

for i in range(1, 3):
    url_json = 'http://interface.sina.cn/pc_zt_api/pc_zt_press_news_doc.d.json?subjectID=64558&cat=&size=40&page='+str(i)+'&channel=sports'
        #构造json数据源的地址
    newsListPages(url_json)

csvfile.close()

六、总结:

request负责获取html页面,json负责解析数据源,bs负责解析html内页获取相关内容(中间涉及编码问题,在stackoverflow找到答案),最后是写入txt(自带函数),写入csv(csv和codecs模块)。

相关TAG标签
上一篇:中断下半部的三种机制
下一篇:知识库--Web+Digester(73)
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站