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

这个页面是新浪英超曼联新闻的首页,直接用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_urlheaders = 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")   #先找到idartibody的元素,再向下寻找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")   #先找到idartibody的元素,再向下寻找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")   #先找到idartibody的元素,再向下寻找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模块)。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

limaning

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值