(廿四)Python爬虫:爬取微博并使用MongoDB存储

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_25343557/article/details/82392399

必知

首先我们需要切记的是我们需要爬取的微博地址为:https://m.weibo.cn。不是https://weibo.com/。因为前者的数据时通过AJAX加载的,有利于我们的抓取,后者难度大,本人找了半天也找不到接口。
本次我们爬取演员张一山的微博。


操作

打开开发者工具,刷新爬取页面,由于微博数据是通过AJAX请求获取的,所以选择XHR 只查看AJAX请求。
这里写图片描述
依次点击AJAX请求查找获取数据的接口。
这里写图片描述
获取的接口为:

https://m.weibo.cn/api/container/getIndex?uid=1776845763&luicode=10000011&lfid=100103type=1&q=张一山&sudaref=login.sina.com.cn&display=0&retcode=6102&type=uid&value=1776845763&containerid=1076031776845763

微博数据的加载时通过滚动来实现的,每一次加载10条数据。
这里写图片描述
我们需要多次获取接口从而找出每次加载数据接口的变化部分,方便自动爬取。第二次加载时的接口为:

https://m.weibo.cn/api/container/getIndex?uid=1776845763&luicode=10000011&lfid=100103type=1&q=张一山&sudaref=login.sina.com.cn&display=0&retcode=6102&type=uid&value=1776845763&containerid=1076031776845763&page=2

到此处我们就能发现接口的关键就是page参数。通过page的改变即可获取每页数据。
以上接口太长了,经过多次测试得出精简版接口:

https://m.weibo.cn/api/container/getIndex?uid=1776845763&type=uid&value=1776845763&containerid=1076031776845763&page=1

注意坑一:
通过返回的json数据我们可以很容易的发现每条微博数据都在data.cards.mblog中,但是第一次加载时需要注意以下内容也会出现在cards中:
这里写图片描述
显然如果去获取mblog是会失败的,我们需要判断以下是否获取成功。

注意坑二:
有的正文中有html标签,最终结果不应该有标签,我们应该将这些标签中的文本内容取出。我们可以通过pyquery提取text。

注意坑三:
获取微博发布时间需要注意以下几种情况:

  • 几小时前
  • 昨天 xx
  • 月-日,表示当年
  • 年-月-日
    所以我们需要对获取到的create_at值进行解析转换。

项目实现代码如下:

from pyquery import PyQuery as pq
from pymongo import MongoClient
from datetime import timedelta,datetime
import requests
import re

client = MongoClient(host='127.0.0.1',port=27017)
db = client.weibo
collection = db.zhangyishan
headers = {
        'Host':'m.weibo.cn',
        'Referer':'https://m.weibo.cn/u/1776845763',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 QIHU 360SE',
        'X-Requested-With': 'XMLHttpRequest'}  # 伪装成浏览器
def created_time(created_at):
    '''
    转换为年-月-日这种形式
    :param created_at: 微博发布时间
    :return: 转换后的微博发布时间
    '''
    if re.compile('\d{4}-\d{2}-\d{2}').match(created_at):
        return created_at
    else:
        if re.compile('\d{2}-\d{2}').match(created_at):
            return datetime.today().strftime('%Y') + '-' + created_at
        else:
            if re.compile('昨天').search(created_at):
                return (datetime.today() + timedelta(-1)).strftime('%Y-%m-%d')
            else:
                return datetime.today().strftime('%Y-%m-%d')
def get_data(url):
    '''
    根据url获取json数据
    :param url: 请求地址
    :return: json形式数据
    '''
    try:
        resp = requests.get(url,headers)
        if resp.status_code == 200:
            print('获取到数据')
            return resp.json()
    except requests.RequestException as e:
        print('获取数据失败')

def parse_data(json):
    '''
    解析json数据
    :param json: json数据
    :return: 生成器
    '''
    if json:
        items = json.get('data').get('cards')#获取所有加载的数据
        for item in items:
            item = item.get('mblog')#获取每条数据的信息
            if item==None:
                continue
            data = {}
            data['weiboid'] = item.get('id')#微博ID
            data['source'] = item.get('source')#微博来源
            #使用pyquery获取html标签内的文本内容
            data['text'] = pq(item.get('text')).text()#微博正文
            data['created_at'] = created_time(item.get('created_at'))#微博发布时间
            data['attitudes_count'] = item.get('attitudes_count')#微博点赞数
            data['comments_count'] = item.get('comments_count')#微博评论数
            data['reposts_count'] = item.get('reposts_count')#微博转发数
            yield data#返回一个生成器


def save_data(data):
    '''
    将微博数据保存到MongoDB中
    :param data: 微博数据
    :return:
    '''
    for item in data:
        if collection.insert_one(item):
            print('保存成功!')

def main(page):
    url = 'https://m.weibo.cn/api/container/getIndex?uid=1776845763&type=uid&value=1776845763&containerid=1076031776845763&page='+str(page)
    data = get_data(url)#获取数据
    data = parse_data(data)#解析数据
    save_data(data)#保存数据

if __name__=='__main__':
    for page in range(1,51):
        print('=======================正在爬取%s页======================='%page)
        main(page)

这里写图片描述

扩展:以上代码获取到的只是微博内容的缩略信息,如果需要爬取全文怎么解决?

猜你喜欢

转载自blog.csdn.net/qq_25343557/article/details/82392399