当前位置:   article > 正文

Python爬虫与信息提取(五)爬虫实例:爬取新浪微博热搜排名_爬虫爬取微博热搜前五十

爬虫爬取微博热搜前五十

经过一段时间的Python网络爬虫学习,今天自己摸索制作了一个能够爬取新浪微博实时热搜排名的小爬虫

1.效果:

2.制作过程中遇到的问题:

(1)一开始研究微博热搜页面的源代码时忽略了<tbody>中还包括一个置顶热搜,它的标签包含结构和其他的50个不同,因此需要单独考虑

(2)难点是标签中信息的获取,需要搞清楚 find_all( ) 函数返回的是列表,只能用于for遍历体系中,针对HTML中的<tbody>下面的<tr>节点,<tr>下面的<tb>子节点,都需要一步一步地find

(3)在一开始不知道如何使用class="td-01"属性直接find到内容,因为python的关键字class会和class=发生重名的情况,经过查阅之后发现,可以使用 class_ 代替 class

https://blog.csdn.net/IMW_MG/article/details/78109199

(4)在获取的时候曾经遇到了问题:使用<>.string获取不到标签中的字符串内容,这种情况会在热搜排名中带有表情emoji时发生,经过调试得到了将string替换为text的解决方法,可以正常地得到字符串的内容

(5)正确地获取到一个存储信息的二维列表之后,还需要按照格式从而正确地打印出来,这又是一个难点。一直遇到了一个问题:在中英混合的字符串中,内置的len( )函数无法正确地计算字符串的字符长度(不是长度!),从而导致了输出排版不整齐的问题。经过查阅之后,有下面的内容解决了这样的问题:

https://www.jb51.net/article/86577.htm

 于是内建了函数length( )来正确获取字符串的字符宽度,从而正确计算所需空格的数量

  1. #获取一个中英文混合的字符串文本的字符宽度部分
  2. widths = [
  3. (126, 1), (159, 0), (687, 1), (710, 0), (711, 1),
  4. (727, 0), (733, 1), (879, 0), (1154, 1), (1161, 0),
  5. (4347, 1), (4447, 2), (7467, 1), (7521, 0), (8369, 1),
  6. (8426, 0), (9000, 1), (9002, 2), (11021, 1), (12350, 2),
  7. (12351, 1), (12438, 2), (12442, 0), (19893, 2), (19967, 1),
  8. (55203, 2), (63743, 1), (64106, 2), (65039, 1), (65059, 0),
  9. (65131, 2), (65279, 1), (65376, 2), (65500, 1), (65510, 2),
  10. (120831, 1), (262141, 2), (1114109, 1),
  11. ]
  12. def get_width(a):
  13. global widths
  14. if a == 0xe or a == 0xf:
  15. return 0
  16. for num, wid in widths:
  17. if a <= num:
  18. return wid
  19. return 1
  20. def length(str):
  21. sum = 0
  22. for ch in str:
  23. sum += get_width(ord(ch))
  24. return sum
'
运行

3.全部代码

  1. import requests
  2. import re
  3. import bs4
  4. #获取一个中英文混合的字符串文本的字符宽度部分
  5. widths = [
  6. (126, 1), (159, 0), (687, 1), (710, 0), (711, 1),
  7. (727, 0), (733, 1), (879, 0), (1154, 1), (1161, 0),
  8. (4347, 1), (4447, 2), (7467, 1), (7521, 0), (8369, 1),
  9. (8426, 0), (9000, 1), (9002, 2), (11021, 1), (12350, 2),
  10. (12351, 1), (12438, 2), (12442, 0), (19893, 2), (19967, 1),
  11. (55203, 2), (63743, 1), (64106, 2), (65039, 1), (65059, 0),
  12. (65131, 2), (65279, 1), (65376, 2), (65500, 1), (65510, 2),
  13. (120831, 1), (262141, 2), (1114109, 1),
  14. ]
  15. def get_width(a):
  16. global widths
  17. if a == 0xe or a == 0xf:
  18. return 0
  19. for num, wid in widths:
  20. if a <= num:
  21. return wid
  22. return 1
  23. def length(str):
  24. sum = 0
  25. for ch in str:
  26. sum += get_width(ord(ch))
  27. return sum
  28. #获取HTML文本
  29. def getHTMLText(url):
  30. try:
  31. #模拟浏览器
  32. kv = {'user-agent':'Mozilla/5.0'}
  33. r = requests.get(url, headers=kv, timeout=30)
  34. r.raise_for_status()
  35. r.encoding = r.apparent_encoding
  36. return r.text
  37. except:
  38. print("InternetError!")
  39. return " "
  40. #解析并且返回HTML文本
  41. def HTMLTextconvert(html):
  42. try:
  43. soup = bs4.BeautifulSoup(html, "html.parser")
  44. return soup
  45. except:
  46. print("HTMLConvertError!")
  47. return " "
  48. #检索HTML中的信息,获取搜索排名信息
  49. #存在置顶的情况,需要特殊判断
  50. def HTMLSearch(html, ranklist):
  51. try:
  52. flag = 0
  53. #找到所有tbody标签下的所有内容,并且遍历所有的儿子节点
  54. for tr in html.find("tbody").children:
  55. #添加判断:获得的内容是否为标签Tag类型
  56. if isinstance(tr, bs4.element.Tag):
  57. #使用flag特判置顶的情况
  58. if flag==0:
  59. rank = "置顶"
  60. #注意由于class属性会和python中的关键字重名,因此需要变为class_
  61. td02 = tr.find_all(class_=re.compile('td-02'))
  62. for i in td02:
  63. if isinstance(i, bs4.element.Tag):
  64. #trans得到的类型为列表
  65. trans = i.find_all("a")
  66. number = " "
  67. ranklist.append([rank, trans[0].string, number])
  68. flag = 1
  69. else:
  70. #排名信息在td标签下的class=td-01属性中
  71. td01 = tr.find_all(class_=re.compile("td-01"))
  72. for i in td01:
  73. if isinstance(i, bs4.element.Tag):
  74. rank = i.string
  75. #热搜内容和搜索量在td标签下的class=td-02属性中:内容是a标签,搜索量是span标签
  76. td02 = tr.find_all(class_=re.compile("td-02"))
  77. for i in td02:
  78. name = i.find_all("a")
  79. column = i.find_all("span")
  80. #使用string获取字符串信息不准确,因为微博还有一些热搜标题为含有表情的,因此使用了text
  81. ranklist.append([rank, name[0].text, column[0].text])
  82. except:
  83. print("HTMLSearchError!")
  84. #打印排名
  85. def Rankprint(ranklist, num):
  86. try:
  87. #先打印表头,总长为70个字符,其中{1}和{3}是变化的空格数量计算,默认为:
  88. #排名*4,空格*3,名称*50,空格*5,点击量*8
  89. a = " "
  90. print("——————————————————————————————————————")
  91. print("{0}{1}{2}{3}{4}\n".format("排名", a*5, "热搜内容", a*45, "搜索量"+a*2))
  92. #使用flag来判断是否输出了置顶内容
  93. flag = 0
  94. for i in range(num):
  95. if flag==0:
  96. print("{0}{1}{2}\n".format(ranklist[i][0], a*3, ranklist[i][1]))
  97. flag = 1
  98. else:
  99. #c是排名有一位、两位的数字,用来纠正空格
  100. c = 7-len(ranklist[i][0])
  101. #根据内容来随时计算所要填充的空格数量b
  102. str = ranklist[i][1]
  103. b = 62-length(ranklist[i][1])-len(ranklist[i][0])-c
  104. print("{0}{1}{2}{3}{4:<8}".format(ranklist[i][0], a*c, ranklist[i][1], a*b, ranklist[i][2]))
  105. print("\n")
  106. except:
  107. print("RankPrintError!")
  108. #主函数
  109. def main():
  110. try:
  111. #微博热搜的网站
  112. url = "https://s.weibo.com/top/summary?Refer=top_hot&topnav=1&wvr=6"
  113. #使用二维列表存储每一条热搜信息的rank信息和内容
  114. rank = []
  115. text = getHTMLText(url)
  116. soup = HTMLTextconvert(text)
  117. HTMLSearch(soup, rank)
  118. Rankprint(rank, 51)
  119. except:
  120. print("SystemError!")
  121. return 0
  122. main()
'
运行

在所有可能发生错误的部分都增加了报错机制,这样程序就更加的具有适应能力了!

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/841410
推荐阅读
相关标签
  

闽ICP备14008679号