当前位置:   article > 正文

如何爬取微博的粉丝_微博粉丝爬取

微博粉丝爬取

一、开发环境

Python版本为3.5;在我程序中使用到的包:requests、lxml、BeautifulSoup4、json等。

  1. pip install requests # 获取网页
  2. pip install lxml # 解析引擎,在BeautifulSoup4中被使用
  3. pip install BeautifulSoup4 # 解析HTML文件,从其中提取信息

本文完整源码:https://github.com/Mannix1994/FindYou,搞清楚本文的细节,抓取别的微博网页应该是易如反掌了。

二、获取粉丝页面的html源码

爬取微博数据的时候,很多页面需要登录自己的微博才能看到,那么,有木有简单的办法 不用再代码中实现登录的功能,就能获取自己想要的页面?答案是有的:

  1. # -*- coding: utf-8 -*-
  2. import requests
  3. from html.parser import HTMLParser
  4. def get_html(header, the_url):
  5. """
  6. 获取the_url指定的网页
  7. :param header: 网页的请求头信息,包含Cookie啊什么的,Cookie就是你登录之后
  8. 的凭证,其他的信息也照抄,伪装成浏览器访问微博,减少封号风险。
  9. :param the_url: 网页网址
  10. :return: 返回下载到的网页
  11. """
  12. r = requests.get(url=the_url, headers=header)
  13. parser = HTMLParser()
  14. parser.feed(r.text)
  15. html_str = r.text
  16. return html_str

其中的header就是网页的请求头(Request Headers)信息。可使用Chrome、Chromium、 Firefox浏览器来获取请求头信息。获取这个请求头部的步骤为:1.登录微博,进入 你要下载的页面; 2、按F12进入开发模式;3. 点击"网络(Network)"选项卡;4. F5 刷新当前页面;5. 在"网络(或Network)"选项卡中点击"HTML(或Doc)";6. 点击一下 你要下载的页面的网址;7. 点击"消息头(或Headers)"选项卡;8. 在该选项卡中的 "请求头(或Request Headers)"就是header里面需要的信息。header的格式在config .py中有例子。

三、解析粉丝页,获取粉丝信息

1. 分析粉丝主页HTML的结构分析粉丝主页HTML的结构

  1. 1 <!doctype html>
  2. 2 <html>
  3. 3 <head>
  4. 4 <!---其他头部信息。。。。-->
  5. 5 <title>李子柒的微博_微博</title>
  6. 6
  7. 7 <!-- $CONFIG -->
  8. 8 <script type="text/javascript">
  9. 9 var $CONFIG = {};
  10. 10 $CONFIG['islogin']='1';
  11. 11 //配置信息.....
  12. 12 </script>
  13. 13 <!-- / $CONFIG -->
  14. 14
  15. 15 </head>
  16. 16 <body class="B_page S_page">
  17. 17 <div class="WB_miniblog">
  18. 18 <div class="WB_miniblog_fb">
  19. 19 <div id="pl_common_top">
  20. 29 </div>
  21. 21 <div class="WB_main clearfix" id="plc_frame">
  22. 22 </div>
  23. 23 <div class="WB_footer S_bg2" id="pl_common_footer">
  24. 24 </div>
  25. 25 </div>
  26. 26 </div>
  27. 27 <div id="pl_common_base"></div>
  28. 28 <div id="pl_common_forword"></div>
  29. 29 <div id="pl_common_dynamicskin"></div>
  30. 30 <div id="pl_lib"></div>
  31. 31 <div id="pl_common_webim"></div>
  32. 32 </body>
  33. 33
  34. 34 <script>
  35. 35 var FM='js脚本'
  36. 36 </script>
  37. 37 <script>FM.view({"domid":"pl_lib",内容...});</script>
  38. 38 <script>FM.view({"ns":"pl.common.webim","domid":"pl_common_webim",内容...})</script>
  39. 39 <script>FM.view({"ns":"pl.top.index","domid":"pl_common_top",内容...})</script>
  40. 40 <script>FM.view({"ns":"page.pl.content.changeLanguage.index","domid":"pl_common_footer","css":[],内容...})</script>
  41. 41 <script>FM.view({"ns":"pl.base.index","domid":"pl_common_base",内容...)</script>
  42. 42 <script>FM.view({"ns":"page.pl.frame.index","domid":"plc_frame",内容...})</script>
  43. 43 <script>FM.view({"ns":"pl.header.head.index","domid":"Pl_Official_Headerv6__1",内容...})</script>
  44. 44 <script>FM.view({"ns":"pl.nav.index","domid":"Pl_Official_Nav__2",内容...})</script>
  45. 45 <script>FM.view({"ns":"","domid":"plc_main","css":[],"html":"内容...",内容...})</script>
  46. 46 <script>FM.view({"ns":"pl.thirdVip.liveSkins.index","domid":"pl_common_dynamicskin",内容...)</script>
  47. 47 <script>FM.view({"ns":"pl.content.navList.index","domid":"Pl_Official_HisRelationNav__58",内容...})</script>
  48. 48 <script>FM.view({"ns":"pl.content.followTab.index","domid":"Pl_Official_HisRelation__59","html":"内容...",内容...})</script>
  49. 49 </html>

观察该HTML源码,可以发现,页面里的内容是通过js脚本载入进去的,从37到48行,每一行的内容包含了在粉丝页面中显示的内容,在经过浏览器渲染(执行37到48的js脚本)以后,会加载到16到31行。例如48行,就是包含了"李子柒"粉丝页的粉丝内容,经过浏览器渲染以后,会加载到页面中指定的位置。

那么,我是怎么确定我要找的粉丝内容在48行的?答案就是打开粉丝页,查看网页源码,然后Ctrl+F查找一个粉丝的信息,比如id,就能发现这个id出现在第48行,这样,我就知道粉丝的信息在48行的js脚本里了。观察48行可以看出"domid":"Pl_Official_HisRelation__59"是该行特有的字符串,不管粉丝的信息怎么变,这段字符串是不变的,因此可以通过find函数来确定是否是粉丝信息所在行。

可以看出,FM.view()是一个函数,参数是一个json数据(类似于python中的Dictionary,也就是键值对),包含粉丝信息的网页数据,就在这个json数据里(粉丝信息对应的key是'html'),所以,在python中,我们可以提取出FM.view()的参数A,然后编写代码json_data = json.loads(A)获得json对象json_data,获取json_data里面的网页数据可通过如下代码获取html_data = json_data['html']html_data就是包含粉丝信息的网页。然后就可以使用BeautifulSoup来解析网页从其中提取你想要的信息。微博的其他网页的结构和这个类似(当然,这里指的是电脑版的微博,手机版的不知道是否相同),具体的代码请看项目中函数的注释,都是非常详细的了。

2. 看懂以下两段代码,解析微博的页面就不成问题了

解析一页的粉丝

  1. def get_fans_list(html_str):
  2. """
  3. 从博主的粉丝页html源码中解析出粉丝
  4. :param html_str: 含有粉丝的网页,模板在README.md文件中
  5. :return: 返回粉丝的一个list
  6. """
  7. # 分割html网页,得到一些包含json数据的字符串
  8. fans_json_list = html_str.split("</script>")
  9. # 找到包含粉丝信息的那个json字符串
  10. json_str = {}
  11. for item in fans_json_list:
  12. # 去除"FM.view"等其他字符,得到一个json格式的字符串
  13. item = get_pure_json(item)
  14. # 如果是空,则继续处理下一个数据
  15. if not item:
  16. continue
  17. # "domid":"Pl_Official_HisRelation__59"是一个粉丝信息页的
  18. # 那一行的一个独特的标识,其他行的都不同,如果一个json字符
  19. # 串包含这个字符串,那么这个json对象就包含粉丝信息。要获取
  20. # 其他信息,也可以通过该行的一个独特的标识来定位。
  21. if item.find('"domid":"Pl_Official_HisRelation__59"') > -1:
  22. json_str = item
  23. # 载入json格式字符串,得到一个dictionary
  24. json_data = json.loads(json_str)
  25. # print(fans_html)
  26. # 使用BeautifulSoup解析,json_data['html']是网页数据,'lxml'是
  27. # 解析html的引擎。关于BeautifulSoup的使用,大家可自行查看文档。
  28. soup = BeautifulSoup(json_data['html'], 'lxml')
  29. # 预处理,打印soup.prettify()的结果,就会看到一个格式化好的html文件
  30. soup.prettify()
  31. # print(soup.prettify())
  32. # 写入文件
  33. # f = open("html/test.html", "w", encoding="UTF-8")
  34. # f.write(soup.prettify())
  35. # 获取html文件里的粉丝
  36. fans = []
  37. for div_tag in soup.find_all('div'):
  38. # 找到包含粉丝列表的div,下面是包含粉丝信息的网页数据形式
  39. # <div class = 'follow_inner'>
  40. # <ul><li><dl>第一个粉丝的信息</dl></li></ul>
  41. # <ul><li><dl>第二个粉丝的信息</dl></li></ul>
  42. # ...
  43. # </div>
  44. if div_tag['class'] == ["follow_inner"]:
  45. # 提取粉丝,<dl>标签里就是粉丝的信息
  46. for fan_dl in div_tag.find_all('dl'):
  47. p = Fan(fan_dl)
  48. # print(p.__dict__)
  49. fans.append(p)
  50. break
  51. return fans

解析一个粉丝,首先给出一个粉丝的html源码,再给出解析这个html源码的代码。

  1. <dl class="clearfix">
  2. <dt class="mod_pic">
  3. <a href="/u/6360029229?refer_flag=1005050008_" target="_blank" title="等的我都下雪了">
  4. <img alt="等的我都下雪了" height="50" src="...jpg" usercard="id=6360029229&amp;refer_flag=1005050008_" width="50"/>
  5. </a>
  6. </dt>
  7. <dd class="mod_info S_line1">
  8. <div class="info_name W_fb W_f14">
  9. <a class="S_txt1" href="/u/6360029229?refer_flag=1005050008_" target="_blank" usercard="id=6360029229&amp; ...">
  10. 等的我都下雪了
  11. </a>
  12. <a>
  13. <i class="W_icon icon_female">
  14. </i>
  15. </a>
  16. </div>
  17. <div class="info_connect">
  18. <span class="conn_type">
  19. 关注
  20. <em class="count">
  21. <a href="/6360029229/follow" target="_blank">
  22. 16
  23. </a>
  24. </em>
  25. </span>
  26. <span class="conn_type W_vline S_line1">
  27. 粉丝
  28. <em class="count">
  29. <a href="/6360029229/fans?current=fans" target="_blank">
  30. 4
  31. </a>
  32. </em>
  33. </span>
  34. <span class="conn_type W_vline S_line1">
  35. 微博
  36. <em class="count">
  37. <a href="/u/6360029229" target="_blank">
  38. 2
  39. </a>
  40. </em>
  41. </span>
  42. </div>
  43. <div class="PCD_user_b S_bg1" node-type="follow_recommend_box" style="display:none">
  44. </div>
  45. <div class="info_add">
  46. <em class="tit S_txt2">
  47. 地址
  48. </em>
  49. <span>
  50. 北京
  51. </span>
  52. </div>
  53. <div class="info_from">
  54. 通过
  55. <a class="from" href="http://app.weibo.com/t/feed/4JpANe">
  56. 微博搜索
  57. </a>
  58. 关注
  59. </div>
  60. </dd>
  61. <dd class="...">其他不解析的数据,我在这里删除了</dd>
  62. </dl>

解析粉丝信息的代码

  1. class Fan(object):
  2. def __init__(self, fan_dl=None):
  3. """
  4. 解析一个粉丝的信息
  5. :param fan_dl: 包含一个粉丝信息的<dl>标签的网页源码
  6. """
  7. self.name = None
  8. self.gender = None
  9. self.url = None
  10. self.id = None
  11. self.address = None
  12. self.followNumber = None
  13. self.fansNumber = None
  14. self.assay = None
  15. self.introduce = None
  16. self.fromInfo = None
  17. self.analysis(fan_dl)
  18. def analysis(self, fan_dl):
  19. self.analysis_name(fan_dl)
  20. self.analysis_gender(fan_dl)
  21. self.analysis_follow_and_fans_number(fan_dl)
  22. self.analysis_city(fan_dl)
  23. self.analysis_introduce(fan_dl)
  24. # self.analysis_follow_way(fan_dl)
  25. self.analysis_id(fan_dl)
  26. def analysis_name(self, fan_dl):
  27. # 获取fan_dl第一个<div>的第一个<a>里面的字符串,也就是粉丝的id
  28. self.name = fan_dl.div.a.string
  29. def analysis_gender(self, fan_dl):
  30. info_tag = None
  31. # 找到所有的<div ...>
  32. for div_tag in fan_dl.find_all('div'):
  33. # 如果<div>的class属性为'info_name W_fb W_f14',就是
  34. # 性别信息所在<div>(<div class="info_name W_fb W_f14">)
  35. if div_tag['class'] == ["info_name", "W_fb", "W_f14"]:
  36. info_tag = div_tag
  37. if info_tag:
  38. # 在info_tag中找到所有的<a ...>...</a>
  39. for tag_a in info_tag.find_all('a'):
  40. # 如果标签a包含<i ...>...<./i>这个标签,就是包含性别信息的标签a。
  41. if tag_a.i:
  42. # 如果<i ...>的class属性等于'W_icon icon_female',就是女性
  43. if tag_a.i['class'] == ["W_icon", "icon_female"]:
  44. self.gender = 'female'
  45. return
  46. # 如果<i ...>的class属性等于'W_icon icon_male',就是男性
  47. elif tag_a.i['class'] == ["W_icon", "icon_male"]:
  48. self.gender = 'male'
  49. return
  50. elif tag_a.get('class', None):
  51. # 如果标签<a>的class属性为'S_txt1',就是包含了粉丝url信息的标签
  52. if tag_a['class'] == ['S_txt1']:
  53. # 获取href属性,得到粉丝的主页地址
  54. self.url = "https://weibo.com" + tag_a['href']
  55. pass
  56. def analysis_id(self, fan_dl):
  57. # 获取粉丝的id
  58. # 第一个<dt>的第一个<a>的href属性
  59. person_rel = fan_dl.dt.a['href']
  60. self.id = person_rel[person_rel.find('=') + 1:-5] + person_rel[3:person_rel.find('?')]
  61. def analysis_city(self, fan_dl):
  62. # 后面的我就不写注释了,和前面的同理
  63. for div_tag in fan_dl.find_all('div'):
  64. if div_tag['class'] == ['info_add']:
  65. address_tag = div_tag
  66. self.address = address_tag.span.string
  67. def analysis_follow_and_fans_number(self, fan_dl):
  68. for div_tag in fan_dl.find_all('div'):
  69. if div_tag['class'] == ["info_connect"]:
  70. info_tag = div_tag
  71. self.followNumber = info_tag.find_all('span')[0].em.string
  72. self.fansNumber = info_tag.find_all('span')[1].em.a.string
  73. self.assay = info_tag.find_all('span')[2].em.a.string
  74. def analysis_introduce(self, fan_dl):
  75. for div_tag in fan_dl.find_all('div'):
  76. if div_tag['class'] == ['info_intro']:
  77. introduce_tag = div_tag
  78. self.introduce = introduce_tag.span.string
  79. def analysis_follow_way(self, fan_dl):
  80. for div_tag in fan_dl.find_all('div'):
  81. if div_tag['class'] == ['info_from']:
  82. from_tag = div_tag
  83. self.fromInfo = from_tag.a.string
  84. def __str__(self):
  85. return "{name: %s, gender: %s,address: %s,id: %s, follow&fan: %s&%s,introduce: %s, url: %s}" % \
  86. (self.name, self.gender, self.address, self.id, self.followNumber,
  87. self.fansNumber, self.introduce, self.url)
  88.  

三、关于我

  1. var whoAmI = {
  2. name : "Mannix1994",
  3. gitee : "https://gitee.com/Mannix1994",
  4. github : "https://github.com/Mannix1994"
  5. }

本文不在更新,最新的内容更新地址:https://github.com/Mannix1994/FindYou

 

 

 

 

 

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号