微博爬虫系列之关键词及指定用户博文爬取

前言

近期的一些微博爬虫内容,本篇主要将怎么根据关键词或指定用户进行博文爬取。

准备写的内容:

定向词及指定用户博文爬取方面,用的是微博网页版(https://weibo.cn)。对于微博网页版中相关博文的爬取,需要使用到cookies。这方面的爬取参考了github上的资源:

https://github.com/nghuyong/WeiboSpider

写的时候发现网页版的关键词检索接口已经不见了···可能是微博删除了网页版的接口吧···之后再看看怎么在pc端爬取。

这里先介绍怎么指定用户进行博文爬取吧···

指定用户博文爬取

指定用户的时候,需要有用户的用户id。通常用户id是一串数字,也有一些账号更改后是字符串,举个例子,何同学跟央视新闻的微博:

老师好我叫何同学:https://weibo.cn/6529876887
央视新闻:https://weibo.cn/cctvxinwen

在这里何同学的uid = 6529876887,央视新闻的uid = cctvxinwen。当然也可以获取到央视新闻以数字存储的id,之后再讲怎么获取,这里直接放出来就是uid = 2656274875,点击可以发现确实是央视新闻的微博https://weibo.cn/2656274875

这个问题在爬取用户博文方面没有影响,不过在爬取用户信息时会有影响,后面写用户信息爬取再说这个情况怎么解决。

下面以央视新闻为例看看怎么爬用户的博文。

获取用户发布的所有博文网页

点击进入央视新闻的微博,可以看到这个账号发布了很多很多微博,在网页版观看就会显示很多页,那么要爬取的时候就要先获取他的页数。

当点击第二页时,会发现url会变成https://weibo.cn/cctvxinwen?page=2。也就是说这个翻页是以page这个字段进行翻页的,这就好办很多了。

page改成1可以发现网页跳转到所有博文的第1页,接下来那我们就先获取到所有的页面url。

首先进入https://weibo.cn/cctvxinwen?page=1,打开开发者模式,在文件中找到自己的cookies

image

接下来将第一页的内容爬下来看看长什么样。

import random
import requests
import re
from lxml import etree
import time

headers = {
       "cookie": cookies,
       "user-agent": get_random_ua(),
    }

user_id = 'cctvxinwen'
url_format = "https://weibo.cn/{}?page={}"
urls = []
url = url_format.format(user_id, 1)
resp = requests.get(url, headers=headers)

在网页开发者模式下,点开文件可以发现没有json格式的数据输出。因此这里不能直接通过解析json数据获取到页面数据。

这里就需要查看网页返回的文本信息了。这里再定位具体信息时,我用的是lxml库里的etree方法。

text = resp.text
tree_node = etree.HTML(resp.text.encode('utf-8'))

这里要查看具体要定位到哪里,可以在网页上的源码进行定位,比如我们要定位到页数,找到页数所在的地方:

image

这里可以看到,总页数放在源码的这个地方:
在这里插入图片描述

在源码搜索mp,发现这个控件就一个,因此我们就可以直接定位到页数,并通过节点的get方法获得属性value,接着就可以把所有页面的url都拿到啦:

page_node = tree_node.xpath('//input[@name="mp"]')[0]
page = int(page_node.get('value'))

urls.append(url)                
for i in range(2, page):
    url = url_format.format(user_id, i) # 第一页的url
    urls.append(url)

print('获取用户{}的url完毕,共{}页'.format(user_id, page))

获取用户博文

拿到用户的所有博文网页后,就可以进行博文的爬取了。这里每一页的数据是一样的,所以直接用第一页为例就可以了。同样的将页面数据爬下来:

url = 'https://weibo.cn/cctvxinwen?page=1'
resp = requests.get(url, headers=headers)
tree_node = etree.HTML(resp.text.encode('utf-8'))

还是在网页上看,定位到某一条博文,可以看到源码是这样子的:


在这里插入图片描述

可以看到第1页这里展示了11条博文(这个不一定),每条博文放在div class="c" id=""的控件里,这里的id是对应的博文id,于是我们就可以拿到博文的控件:

tweet_nodes = tree_node.xpath('//div[@class="c" and @id]')

选择其中一个博文来看


image

这里我们可以看到要的信息全在这里了,接着就按着控件抓信息。这里拿其中一个节点为例。

首先获取微博的url以及微博id,这个从上面看到,可以从点赞、转发、评论处的链接获取,这里选择最简单的转发链接,对应的点赞数、转发数、评论数也可以顺便爬下来了:

tweet_node = tweet_nodes[0]
tweet_data = {}

tweet_repost_url = tweet_node.xpath('.//a[contains(text(),"转发[")]/@href')[0]    
user_tweet_id = re.search(r'/repost/(.*?)\?uid=(\d+)', tweet_repost_url)

tweet_data['user_id'] = user_tweet_id.group(2) # 用户id
tweet_data['weibo_id'] = user_tweet_id.group(1) # 微博id

like_num = tweet_node.xpath('.//a[contains(text(),"赞[")]/text()')[-1]
tweet_data['like_num'] = int(re.search('\d+', like_num).group()) # 点赞数

repost_num = tweet_node.xpath('.//a[contains(text(),"转发[")]/text()')[-1]
tweet_data['repost_num'] = int(re.search('\d+', repost_num).group()) # 转发数

comment_num = tweet_node.xpath(
    './/a[contains(text(),"评论[") and not(contains(text(),"原文"))]/text()')[-1]
tweet_data['comment_num'] = int(re.search('\d+', comment_num).group()) # 评论数

接下来看下微博的创建时间,这里我们看到还有微博的来源,有一些可能会没有这个信息:

create_time_info_node = tweet_node.xpath('.//span[@class="ct"]')[-1]
create_time_info = create_time_info_node.xpath('string(.)')
if "来自" in create_time_info:
    tweet_data['created_at'] = time_fix(create_time_info.split('来自')[0].strip()) # 微博发表时间
    tweet_data['tool'] = create_time_info.split('来自')[1].strip() # 发布微博的工具
else:
    tweet_data['created_at'] = time_fix(create_time_info.strip())

接下来就是博文的主体了:


image

博文方面的内容提取基本就是从github上搬过来的,对内容部分字符串进行了一些匹配清洗:

keyword_re = re.compile('<span class="kt">|</span>|原图|<!-- 是否进行翻译 -->|<span class="cmt">|\[组图共.+张\]')
emoji_re = re.compile('<img alt="|" src="//h5\.sinaimg(.*?)/>')
white_space_re = re.compile('<br />')
div_re = re.compile('</div>|<div>')
image_re = re.compile('<img(.*?)/>')
url_re = re.compile('<a href=(.*?)>|</a>')

def extract_weibo_content(weibo_html):
    s = weibo_html
    if 'class="ctt">' in s:
        s = s.split('class="ctt">', maxsplit=1)[1]
    s = emoji_re.sub('', s)
    s = url_re.sub('', s)
    s = div_re.sub('', s)
    s = image_re.sub('', s)
    if '<span class="ct">' in s:
        s = s.split('<span class="ct">')[0]
    splits = s.split('赞[')
    if len(splits) == 2:
        s = splits[0]
    if len(splits) == 3:
        origin_text = splits[0]
        try:
            retweet_text = splits[1].split('转发理由:')[1]
        except:
            retweet_text = ''
        s = origin_text + '转发理由:' + retweet_text
    s = white_space_re.sub(' ', s)
    s = keyword_re.sub('', s)
    s = s.replace('\xa0', '')
    s = s.strip(':')
    s = s.strip()
    return s
    
tweet_html = etree.tostr
ing(tweet_node, encoding='unicode')
tweet_data['content'] = extract_weibo_content(tweet_html) # 微博内容

上面是比较简单的博文情况,有一些可能有图片、视频、转发等情况,这里直接放GitHub的做法,具体爬取方式是一样的,定位控件,找信息:

 #### 图或视频
images = tweet_node.xpath('.//img[@alt="图片"]/@src')
if images:
    tweet_data['image_url'] = images  # 图片
    for img in images:
        fileName = '{}_{}_{}'.format(tweet_data['user_id'], user_name, tweet_data['weibo_id'])
        try:
            savePics(img, user_name, path = 'D:/课题工作/data/black/userContentPic')
        except:
            pass
        
videos = tweet_node.xpath('.//a[contains(@href,"https://m.weibo.cn/s/video/show?object_id=")]/@href')
if videos:
    tweet_data['video_url'] = videos # 视频

#### 转发类的原始微博
repost_node = tweet_node.xpath('.//a[contains(text(),"原文评论[")]/@href')
if repost_node:
    tweet_data['origin_weibo'] = repost_node[0] # 原始微博,只有转发的微博才有这个字段

#### 获取微博内容
all_content_link = tweet_node.xpath('.//a[text()="全文" and contains(@href,"ckAll=1")]')
if all_content_link:
    all_content_url = base_url + all_content_link[0].xpath('./@href')[0]
    count = 0
    while count < 10:
        try:
            tmp_res = requests.get(all_content_url, headers=headers)
            tmp_tree_node = etree.HTML(tmp_res.text.encode('utf-8'))
            content_node = tmp_tree_node.xpath('//*[@id="M_"]/div[1]')[0]
            tweet_html = etree.tostring(content_node, encoding='unicode')
            tweet_data['content'] = extract_weibo_content(tweet_html)
            break
        except:
            count += 1
            if count == 10:
                tweet_html = etree.tostring(tweet_node, encoding='unicode')
                tweet_data['content'] = extract_weibo_content(tweet_html) # 微博内容
            time.sleep(5)
else:
    tweet_html = etree.tostring(tweet_node, encoding='unicode')
    tweet_data['content'] = extract_weibo_content(tweet_html) # 微博内容

这篇又结束了!

到这里,指定用户的博文爬取就结束了,主要还是参考了GitHub的大神~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353