曼城新闻情报站(一)爬取3大网站的曼城新闻

想完成一个Django框架的爬虫,将曼城的新闻内容爬到并放入数据库,然后通过Django框架用网页显示出来。现在第一步是爬新浪、网易、腾讯的曼城新闻内容并放入Mongodb中。本来搜狐也是一个计划中的门户网站,但是爬出来的内容中文不能正常显示,不像是编码的问题,于是就直接跳过了。

 

这个程序关键的地方是新浪和网易的球队新闻都是js动态显示的,新浪还是json格式的网页,要找到真正的目的网页还是费了一些周章的。由于新闻具有时效性,所以只抓了首页的新闻内容,避开了逐个翻页的麻烦。

来看看网易的真实网址。查看元素,选JS,然后鼠标指到曼城可以看到多了个js地址,点进去找到URL打开。

这样的网页内容看似一个字典的样子,但我没找到简单的方法把想要的数据取出来,直接用的正而表达式取数据。

 

新浪的方法一样,不过新浪用的js翻页,用正则取出了一个json文件,再抓数据。

现在上代码

#-*- coding:utf-8 -*-
#_author:John
#date:2018/9/10 19:37
#softwave: PyCharm
from bs4 import BeautifulSoup
from datetime import datetime
import requests
import re, json
import pymongo

class Man_City():
    def __init__(self):
        self.header = {
            'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
            'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
        }

    def news_man(self):
        #这是js动态生成的页面,需要找到对应的js网页,再用正则表达式找到所需内容
        man_163_url = 'http://sports.163.com/special/000587PO/newsdata_epl_mch.js?callback=data_callback'
        man_163_data = requests.get(man_163_url, headers=self.header)
        man_163_soup = BeautifulSoup(man_163_data.text, 'lxml').get_text()
        title_re = re.compile('title\":\"(.*?)\",')
        url_re = re.compile('docurl\":\"(.*?)\",')
        tienum_re = re.compile('tienum\":(\d+),')
        pub_date_re = re.compile('time\":\"(.*?)\",')

        titles = title_re.findall(man_163_soup)
        urls = url_re.findall(man_163_soup)
        tienums = tienum_re.findall(man_163_soup)
        pub_dates = pub_date_re.findall(man_163_soup)

        for title, url, tienum, pub_date in zip(titles, urls, tienums, pub_dates):
            data = {
                'title': title,
                'url': url,
                # 'tienum': tienum,
                #将字符串的时间转换成时间模式再传入数据库,以便之后以时间进行排序
                'pub_date': datetime.strftime(datetime.strptime(pub_date, '%m/%d/%Y %H:%M:%S'), '%Y-%m-%d %H:%M:%S')

            }
            print(data)
            self.add_to_mongodb(db_name='163', data=data)

    def sina_man_news(self):
        #跟163一样先找到真正的网页,得到的是一个json格式的页面,转换一下再取内容
        url = 'http://interface.sina.cn/pc_zt_api/pc_zt_press_news_doc.d.json?subjectID=68265&cat=&size=40&page=1&channel=sports&callback=jsonpcallback1536942563301'
        data_get = requests.get(url, headers= self.header)
        #获取的网页内容大括号里面的是json数据,用正则表达式获取大括号里面的内容得到json格式数据
        data_re = re.compile('\((.*?)\)')
        soup_data = data_re.findall(data_get.text)[0]
        soup = json.loads(soup_data)
        for i in soup['result']['data']:
            # 观察发现日期是放在url中的,把日期分离出来
            pub_date_soup = i['url'].split('/')[-2]
            data = {
                'title': i['title'],
                'url': i['url'],
                #转换时间格式
                'pub_date':datetime.strftime(datetime.strptime(pub_date_soup, '%Y-%m-%d'), '%Y-%m-%d')
            }
            print(data)
            self.add_to_mongodb(db_name='sina', data=data)

    def qq_man_news(self):
        #腾讯里面的曼城新闻没有用js生成,是静态的网页,直接用bs4获取
        url='http://sports.qq.com/premierleague/'
        data_get=requests.get(url, headers=self.header)
        soup = BeautifulSoup(data_get.text, 'lxml')
        titels = soup.select('.newsul.newsCont3 .news_txt a')
        for i in titels:
            # 跟新浪一样的,日期包含在url中
            pub_date_soup = i.get('href').split('/')[-2]
            data = {
                'title': i.get_text(),
                'url': 'http://sports.qq.com/'+ i.get('href'),
                #转换时间格式
                'pub_date':datetime.strftime(datetime.strptime(pub_date_soup, '%Y%m%d'), '%Y-%m-%d')
            }
            self.add_to_mongodb(db_name='qq', data=data)
            print(data)

    def add_to_mongodb(self, db_name, data):
        #分别命名存入数据库
        client = pymongo.MongoClient('localhost', 27017)
        Man_City = client['Man_City']
        db_name = Man_City[db_name]
        #用日期倒序排列,取出60个标题放到列表,如果新获取的数据标题不在这60个标题列表中就加入数据库中,避免同一个新闻多次存入数据库
        pipeline= [
            {'$sort':{'pub_date':-1}},
            {'$limit':60,},
        ]
        titel_list = [db['title'] for db in db_name.aggregate(pipeline)]
        if data['title'] not in titel_list:
            db_name.insert_one(data)

if __name__ == '__main__':
    M = Man_City()
    M.news_man()
    M.sina_man_news()
    M.qq_man_news()
    # M.add_to_mongodb(db_name='sina')

 

 

为了后面按新闻日期排序,所以在把数据存入数据库前把新闻日期一栏全部转换成了日期格式。存入数据库前取最近存入的60条新闻来比对获得的新闻是不是已经在数据库中了,避免多次存入同一条新闻。

最后的成果如下

现在只是完成了获取数据的第一步,后面还需要用到Django框架,把获取到的数据在网页中显示出来。

posted @ 2018-09-25 01:03  放脚一搏  阅读(647)  评论(0编辑  收藏  举报