[Python] 抓取微博指定博主博文,包含转发博文

最近自学了Python,所以就想把自己学的东西分享出来,写的很初级,如有错误请指正,谢谢

本文仅供学习!!!

从微博中抓取的数据我用了两种方式保存,一种是mongo,一种是mysql.

项目结构

__init__.py 是配置文件,包括日志配置,mongo配置以及mysql配置

data_grap.log是打印日志的文件

run.py 是运行Python程序的入口

service.py就是程序的主要业务代码

环境以及微博接口

1. 使用Python3以上

2. mysql编码为utf8mb4(抓取的数据有表情)

3. 因为抓取数据,我要模拟浏览器请求接口,所以需要抓取的接口,以及请求头,具体如下

detail_url = 'https://m.weibo.cn/detail/'
host = 'm.weibo.cn'
base_url = 'https://%s/api/container/getIndex?' % host
# 这里的user_agent是网上找的
user_agent = 'User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, ' \
             'like Gecko) Version/9.0 Mobile/13B143 Safari/601.1 wechatdevtools/0.7.0 MicroMessenger/6.3.9 ' \
             'Language/zh_CN webview/0 '

  这些数据都是在网上找到,自己可以网页请求微博接口,就可以看到,urser_agent 可能不一样

业务代码

1. 抓取微博数据

# 抓取微博数据
def get_data(page, user_id):
    headers = {
        'Host': host,
        'Referer': 'https://m.weibo.cn/u/%s' % user_id,
        'User-Agent': user_agent
    }

    params = {
        'type': 'uid',
        'value': user_id,
        'containerid': int('107603' + user_id),
        'page': page
    }
    url = base_url + urlencode(params)
    try:
        res = requests.get(url, headers=headers)
        if res.ok == 1:
            return res.json()
        elif res.status_code == 418:
            logger.info("接口冷却中! 无法爬取!")
            return '418'
    except requests.ConnectionError as e:
        logger.info("抓取错误:" + str(e))
    finally:
        # 微博接口限制请求,睡3秒在请求
        time.sleep(3)

以上代码就是模拟浏览器请求访问微博接口的代码,主要包括请求头,参数和请求url.由于微博对接口的访问有限制,频繁请求会返回418状态码,这个意思就是频繁访问,需要等一会才可以.所以我在finally中加了个睡眠.

 还有就是有意要注意的就是拼接请求url的时候,参数要使用urlencode处理一下,否则会报错.

2. 分析数据并保存

 Python抓取数据最重要的就是分析数据,拿到自己想要的东西,一下是分析抓取数据的代码:

# 分析数据并保存
def analysis_data(json, st, rst):
    if json is None or json.get('data') is None or json.get('data').get('cards') is None:
        logger.info("当前页没有数据")
        return 'None'
    items = json.get('data').get('cards')
    for item in items:
        if item.get('card_type') == 9:
            blog = item.get('mblog')
            # 判断是否是转发微博
            if blog.__contains__('raw_text'):
                ret_info = blog.get('retweeted_status')
                mb = ret_info.get('text')
                # 判断是否过滤
                if st == '' and rst == '':
                    save_data(blog, ret_info)
                else:
                    if blog.get('raw_text').find(st) > 0 or mb.find(rst) > 0 or blog.get('text').find(st) > 0:
                        save_data(blog, ret_info)
            else:
                msg = blog.get('text')
                # 判断是否过滤
                if st == '':
                    save_data(blog, None)
                else:
                    if msg.find(st) > 0:
                        save_data(blog, None)

  首先说一下这个方法的入参,json就是待处理的json数据,st和rst是抓取的话题,st是获取博主发布的微博,rst是获取博主转发的微博.因为,博主的博文不一定都是自己想要的,所以就加了这个过滤的功能,当然你不传这两个参数就会抓取你指定多少页,就会抓取多少页博主的博文.

  这段代码就是处理json文本格式的数据,没什么东西,具体需要自己去浏览器中分析.

3. 保存数据

  这里使用两种方式:一种mongo,一种mysql,以下是具体代码:

def save_data(blog, ret_info):
    if ret_info is not None:
        mb = ret_info.get('text')
        data['w_url_0'] = detail_url + ret_info.get('id')
        data['w_type'] = '转发微博'
        data['w_pics_0'] = save_pics(ret_info)
        data['w_content_0'] = pq(mb).text()
        if ret_info.get('user') is not None:
            data['w_id_0'] = ret_info.get('user').get('id')
            data['w_name_0'] = ret_info.get('user').get('screen_name')
    else:
        data['w_type'] = '发布微博'
    msg = blog.get('text')
    data['w_pics_1'] = save_pics(blog)
    data['w_url_1'] = detail_url + blog.get('id')
    data['w_id_1'] = blog.get('user').get('id')
    data['w_name_1'] = blog.get('user').get('screen_name')
    data['w_content_1'] = pq(msg).text()
    data['w_time'] = blog.get('created_at')
    # 0代表转发微博; 1:代表发布微博
    data['_id'] = ('0' if (data['w_type'] == '转发微博') else '1') + "-" + str(data['w_id_1']) + "-" + str(time.time())
    # 使用mongo保存
    conn = mongodb.get_collection(collection_name)
    conn.save(data)
    # 使用mysql保存
    save_data_in_mysql(data)


def save_pics(p_info):
    p = ''
    pics = p_info.get('pics')
    if pics is not None:
        for pic in pics:
            # 字符串拼接图片列表
            p += str(pic.get('url')) + ';'
    return p


def save_data_in_mysql(value):
    sql = 'insert into tb_wb_info (_id, w_id_1, w_id_0, w_name_1, w_content_1, w_url_1, w_pics_1, w_name_0, ' \
          'w_content_0, w_url_0, w_pics_0, w_type, w_time, create_time) value ' \
          '(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);'
    try:
        # 检查SQL连接是否关闭,关闭重连
        sql_conn.ping(reconnect=True)
        # 游标执行SQL语句
        cursor.execute(sql, (value['_id'], value['w_id_1'], value['w_id_0'], value['w_name_1'],
                             str(value['w_content_1']), value['w_url_1'], value['w_pics_1'], value['w_name_0'],
                             str(value['w_content_0']), value['w_url_0'], value['w_pics_0'], value['w_type'],
                             value['w_time'], datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
        sql_conn.commit()
    except Exception as e:
        logger.info('保存mysql错误: ' + str(e))
        sql_conn.rollback()
    finally:
        sql_conn.close()

  这是保存数据的代码,具体需要注意已经写上注释了.

4. 源码

  1. github源码地址: https://github.com/shawnshawnshawn/python_grab_wb.git

  2. 本人邮箱: jiangliuer_shawn@outlook.com. 有问题可以私信,但不能保证会及时回复,望见谅.

这次的分享就到这,下次再见

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值