网站导航

新闻资讯

当前位置:首页 > 新闻资讯

基于社交网络爬虫分析人物兴趣属性(一)

发布时间:2019-12-19

简要描述:

原创: Smity 合天智汇推特爬虫爬取用户id和所有tweets(免登录,不使用api)所有代码都已经发布在github上:https://github.com/smityliu/spider这次做的一个项目中涉及人物画像,做人...

详细介绍

原创: Smity 合天智汇

推特爬虫爬取用户id和所有tweets(免登录,不使用api)所有代码都已经发布在github上:https://github.com/smityliu/spider这次做的一个项目中涉及人物画像,做人物画像中兴趣属性很关键的一点就是要收集足够多的人物数据,基础工作就是进行爬虫的书写,收集数据集。对于一个社交网络来说,这里最大最实用的数据**就是用户发布的帖子,因为里面的东西会关联到个人的兴趣爱好,甚至工作生活,从中做主题提取就可以大致的看出来人物在这个社交网络上所体现出来的一个兴趣属性。经久不衰的话题----白帽子安全条款:不用爬虫爬取个人隐私!所以我对于社交网络的选择标准:1.国外社交网络-----推特;2.只爬取网站上公开发布的用户信息。由于模拟登录过于频繁还是会被网站封ip和账号,因此就想能不能实现免登录状态下的爬虫,爬取用户数据。

用户id爬取

推特上用来标识用户身份的标志可不是用户名,因为用户名是可以重复的,比如我搜索tolly这个用户,会发现有好多用户名叫tolly的。

v2-288affbec031e01bbcca3aefa0004b75_hd.j

但是他们的用户id却是唯一的:

v2-f795975e74a9dea5da85c055abc70bb9_hd.j

红色框中的就是用户id。即使用户名相同,id也不会相同,那么我们来看一下用户主页:这里随便找了一个国外小哥的主页,发现其实域名就是twitter.com + 用户id。

v2-84c50cef25fe8dd2903135b832f0f26e_hd.j

因此我们首先要通过爬虫获取到用户id,才能进行下一步的数据爬取:查询的api接口为:https://twitter.com/search?f=usersdiv>标签中的data-name参数中,然后data-screnn-name和下一段的span class中都有着MrNastyPantz这个id,影响不大,你选择哪个标签做正则都是可以的。

我选择的是data-name和span,个人观念是最好不在同一个标签中做正则提取,会有很多意想不到的问题。因此这个正则这么写:用户名:

data-name="(.*?) data-protected="false"Id:span class="username u-dir" dir="ltr">@b class="u-linkComplex-target">(.*?)/b>/span>

所以加入正则以后的爬虫代码为:

import requestsimport reimport sys#查询用户名idurl='https://twitter.com/search?f=usersspan class="username u-dir" dir="ltr">@b class="u-linkComplex-target">(.*?)/b>/span>',text))

运行命令为:Python twitter_userid_sucess.py + 你要爬取的用户名(在搜索框输入的东西)运行效果为:

v2-e6d8cdd400f768be7ed6da8a20d0fd79_hd.j

上面为用户名,对应下面的id。因为有输入一个smity会有很多用户与之相似,所以会有不止一个结果。用户tweets爬取做完了id的爬取,我们自然就可以直接通过id定位到你想爬取的用户tweets主页。我选取的是https://twitter.com/BeSmity一个社交网络类似*博,推特,脸书这样的,有没有实现免登录爬取信息的可能性,就要看你在不登录的状态下,能否通过浏览器页面看到你想看的信息,推特页面如下:

v2-661439eeccb30da16a2342b9448ceb80_hd.j

可以看到这里我们是在一个没有登录的状态下,看到了该用户的tweets和个人简介还有用户id,然后我们利用鼠标滚轮下滑。不断的往下翻就可以看到这个用户的所有推文,代表着其实我们不用登录推特账户就可以看到这个用户的很多信息。

v2-81eb2e2ef01352f3915e5ad4fdd5731f_hd.j

但是也有一部分信息看不到,比如我们点击这个用户的粉丝和关注页面,或者点击用户头像,会发现其实还是需要登录以后才可查看。

v2-76fd7756ecec70566d31511b93ee4ab4_hd.j

有了这个,我们就来看我们当然想到可以用requests直接请求页面,于是这里很多人就会考虑到直接,requests.get(‘https://twitter.com/BeSmity’),我们看一下返回结果:

v2-7f7b3b11ac379e9cdcaf1f8310d15bee_hd.j

确实有抓到这个用户的tweets,但是发现好像这个只是一条在11月25号的tweets,这个帖子之后还有很多帖子我们没有看到,但是我们明明是可以看到所有的推文的啊,这里却显示了一部分,这个是怎么回事呢?

v2-0f3d8dcf3e6c6ac748ca64bb97bac008_hd.j

我们尝试着继续滚轮下滑,然后发现每滚过一段距离,就会有一个短暂的卡顿,于是我们截取那个卡顿发送的网络数据包:

v2-29024b4d64643c32a3fa50617549663b_hd.j

原来这个卡顿是发送了一个ajax请求,来进行进一步的页面获取,俗称异步页面更新,也就是在不刷新页面的情况下,直接更新页面的内容,可以保证用户不用每次都重新打开页面查看新内容。

所以我们只请求https://twitter.com/BeSmity是绝对不够,他只会返回第一次异步更新之前的值,所以我们需要自己手动模拟这个ajax请求。观察数据包,我们可以看到红色箭头指向的地方有一个max_position,为什么关注这个,一个是因为它有position这个标志位,另外一个是因为这个请求的返回包里面有一个min_position。

v2-ca186a0fff998768c5b9b03048b15e27_hd.j

这个min_position恰好就在第一个,所以我们记录一下当前的这两个标志位。max_position=1197617887390900237min_position=1184647192977514496然后我们继续滚动鼠标滚轮翻页看看会有什么内容突然又是一阵卡顿,我们知道这个时候网页又发送了一个异步更新请求了,赶紧截取查看一下流量包:

v2-8cf50415d5568a143ed2036d7e6753d7_hd.j

复制一下请求的url,我们发现这个时候的max_position变成了上一次ajax请求时返回包中的min_position。

https://twitter.com/i/profiles/show/BeSmity/timeline/tweets?include_available_features=1p class="TweetTextSize TweetTextSize--normal js-tweet-text tweet-text" data-aria-label-part="0">*****/p>

但是由于语言的不同,这个标签还会有如下形式:

p class="TweetTextSize TweetTextSize--normal js-tweet-text tweet-text" data-aria-label-part="0">*****/p>p class="TweetTextSize TweetTextSize--normal js-tweet-text tweet-text" data-aria-label-part="0">*****/p>

因此我们依据标签中都有的data-aria-label-part属性设置取出帖子文本的正则为:

content=re.findall(r'data-aria-label-part="0">(.*?)/p>',text)

这样提取之后,我们的内容就被简化为如下效果:

v2-48d551ea911147cd9a14555752a523b4_hd.j

会发现还是有很多杂质在里面

提取步骤三因此我们继续做如下处理,首先分析提取的东西结构,里面含有很多a>标签和unicode编码字符,@其他用户的语句,以及一些固定的url,我们都将其去除或者替换。

v2-4139bf837f289210692cc142d0b2ea39_hd.j

pattern =re.compile(r'[^>]+>|pic.twitter.com/.*|http(.*?)|',re.S)line = re.sub(pattern ,'',line)line = re.sub('' ,'\'',line)line = re.sub('','',line)line = re.sub('','>',line)line = re.sub('','','"',line)line = re.sub(r'^@(.*?) @(.*?) |^@(.*?) ','',line)

这样的到的就是我们干净的文本,每一行的内容都是一个tweets。

v2-f16fd7bb4c8b4e19dce283a21b3ef343_hd.j

最后加上我们的新请求构造,取下一个max_position的页面内容

tweets=requests.get(url+'/p>',text)    for line in content:      #把多余标签,pic.twitter.com和url去掉      pattern = re.compile(r'[^>]+>|pic.twitter.com/.*|http(.*?)|',re.S)      line = re.sub(pattern ,'',line)      line = re.sub('' ,'\'',line)      line = re.sub('','',line)      line = re.sub('','>',line)      line = re.sub('','','"',line)      line = re.sub(r'^@(.*?) @(.*?) |^@(.*?) ','',line)      if(len(line)):        #continue        f.write(line+'\n')    tweets=requests.get(url+'&max_position='+text_json["min_position"]+'&reset_error_state=false',proxies=proxies)    text_json=json.loads(tweets.text)print("finish work")

代码运行后,每爬取一个页面就会返回下一个页面的max_position,如果没有下一页,就会结束爬取。

v2-232f7008c15b8d5631a96c1d2e201d77_hd.j

可以提前用ctrl+c结束脚本运行,不论是否爬取完毕,都会在同目录下生成一个text.txt文件用于存放爬取的数据。下一章节我们将继续分析如何利用这些爬取的数据进行主题提取。

相关实验:

Python爬虫-基础:

实验:Python爬虫-基础(合天网安实验室)

(了解爬虫的基本原理,对爬虫有简单的认识)

声明:笔者初衷用于分享与普及网络知识,若读者因此作出任何危害网络安全行为后果自负,与合天智汇及原作者无关!


 


推荐产品

如果您有任何问题,请跟我们联系!

联系我们

Copyright © 武汉网盾科技有限公司 版权所有 备案号:鄂ICP备2023003462号-5

地址:武汉市东湖高新区光谷大道光谷世贸中心A栋23楼

在线客服 联系方式 二维码

服务热线

18696195380/18672920250

扫一扫,关注我们

关闭