python 爬取微博热门话题榜
前⾔
python 的爬⾍应该是⽐较⽕热的,趁着国庆闲来⽆事,爬取⼀下微博热搜榜,也算是把之前⽤过的爬⾍在博客简单的温习和记录⼀下。
爬⾍定义
引⽤⾃
⽹络爬⾍(英语:web crawler ),也叫⽹络蜘蛛(spider ),是⼀种⽤来⾃动浏览的。其⽬的⼀般为编纂。
爬⾍策略
选择策略
要爬取的url
页⾯元素
页⾯的链接
重新访问的策略
⽹站更新
页⾯变化
过度访问
爬⾍和反爬⾍
IP 代理池
访问次数
< 协议
并⾏策略
多线程运⾏爬⾍
同⼀页⾯的重复爬取
python 爬⾍
获取数据
基本概念罗列完成了,我们就需要⼀个实战来简单的体验⼀下爬⾍,思来想去,最后选择微博热点事件,进⾏数据爬取,实现⼀个简单的爬⾍。
微博热点榜单⽹址:打开⽹址看看
python正则表达式爬虫这就是⼀个简单的排⾏榜,我们将在这个页⾯进⾏⼀次爬⾍,⾸页我们对这个页⾯需要进⾏⼀个分析,我们需要爬取那些数据。
我们可以看到箭头所指的部分,分为以下三种:
热点内容,热点浏览次数,热点类型
我们将对这三个数据进⾏获取,那么怎么获取呢,我们来看看
python 有⼀个很⽅便的库,可以对⽹页的内容进⾏获取,requests 库
pip install requests
我们先试试获取⼀下
可以看到三⾏代码,我们就获取到了微博热搜榜的⽹页内容。
内容获取到了,我们需要对HTML 内容进⾏解析,获取到我们想要的内容。
解析数据有很多的⽅式,⽐如正则表达式,字符串,beautifulsoup4等
在这⾥我们选择beautifulsoup4去进⾏解析,主要是⽅便易⽤。
解析⽹页数据
安eautifulsoup4解析HTML ⽂档的库
pip install beautifulsoup4
安装lxml 解析库
pip install lxml
beautifulsoup4常见的解析库和优缺点
解析器
使⽤⽅法优势劣势Python 标准库BeautifulSoup(markup, "html.parser")1.Python 的内置标准库2.执⾏速度适中
3.⽂档容错能⼒强
Python 2.7.3 or 3.2.2)前的版本中⽂档容错能⼒差lxml HTML 解析器BeautifulSoup(markup, "lxml")  1.速度快
2.⽂档容错能⼒强
需要安装C 语⾔库lxml XML 解析器BeautifulSoup(markup, ["lxml-xml"])
BeautifulSoup(markup, "xml")  1.速度快
2.唯⼀⽀持xml 的解析器需要安装C 语⾔库
html5lib BeautifulSoup(markup, "html5lib")  1.最好的容错性2.以浏览器的⽅式解析⽂档3.⽣成HTML5格式的⽂档
1. 速度慢
2.不依赖外部扩展
beautifulsoup4的安装已经介绍完了,获取到数据之后我们要进⾏的就是解析数据了。
我们先看看⽂档
⾥⾯有详细的说明教程。我们就不⼀⼀列举了。
这⾥只选择我们这次使⽤的进⾏简单的说明,在说明之前我们⾸先先⽤chrome看看我们需要解析那些数据:
使⽤F12开发者⼯具查看之后我们所需要的数据就在箭头所指的部分。
这个⼀个HTML表格,我们需要获取所有的tr节点⾥⾯的这三个⽂本,⼀起来吧。
⽣成解析对象
soup = BeautifulSoup(htmls, 'lxml')
获取tag信息
ranks = soup.find_all('td', class_='td-01 ranktop')
tags = soup.find_all('td', class_='td-02')
获取⽂本信息
ranks.string
获取⼦节点的tag信息
tags.a
好了我们所能⽤到的就是这些了。刚才数据已经获取到了,我们⼀起来看看,解析后的数据。
def analysis(self):
"""提取数据"""
results = []
htmls = _html()
soup = BeautifulSoup(htmls, 'lxml')
ranks = soup.find_all('td', class_='td-01 ranktop')
tags = soup.find_all('td', class_='td-02')
hots = soup.find_all('td', class_='td-03')
for rank, tag, hot in zip(ranks, tags, hots):
results.append(
(rank.string if rank else 0,
tag.a.string,
tag.span.string if tag.span else 9999999,
hot.i.string if hot.i else ''))
return results
我们分别通过三个find_all⽅法获取到所有的⽂本,然后通过zip⽅法把每⼀组放在各⾃的列表中。
数据排序
在这个⾥⾯添加的数据是按照正常的顺序排列的,但是我的不想把数据按照正序排列,我希望能按照倒序排列,就是浏览次数少的在前⾯。应该怎么实现呢,我们需要借助python的sorted⽅法进⾏⼀次倒序排列。
def __sort(self):
result = self.analysis()
return sorted(result, key=lambda x: int(x[2]), reverse=False)  # 反向排序
通过sorted⽅法并指定阅读数量为排序的key,我们实现了倒序的排列。
展⽰数据
数据也获取到了,也进⾏排序了我们接下来就需要对获取的数据进⾏⼀个展⽰了。
我们需要把数据展⽰⼀种好看的形式,⽐如下⾯这种:
想要实现下⾯这种⾃⼰写的话⽐较⿇烦,我们可以中python的第三⽅库,来实现这个表格打印。
⾸先我们安装⼀下。
pip install prettytable
然后编写展⽰数据的代码:
from prettytable import PrettyTable
tb = PrettyTable()
sorts_data = self.__sort()
tb.field_names = '排名,热点话题,阅读数,热点类型'.split(',')
for i in sorts_data:
tb.add_row(i)
print(tb)
然后我们执⾏,很快执⾏结果出来了,结果打印出来了,但是却报错了。
RecursionError: maximum recursion depth exceeded in comparison
超过最⼤递归数,什么⿁,这个问题我查了很久终于到了问题所在
在prettytable源码的第1253⾏和1255⾏
有⼀个deepcopy⽅法,我们把它去掉就可以了。
⾄于为什么,原因是这样的,deepcopy在python中是深复制和浅复制的不同是,复制完成后和原来的变量是有所不同的,内存地址变了,导致我们在运⾏过程中由于每次的sorts_data列表会被不停的复制,然后每次的内存地址不⼀样,会⼀直在执⾏,所以会陷⼊递归调⽤。所以我们只要删除这个深复制⽅法就好了,执⾏的时候就不会出现最⼤递归的报错了。
函数去掉后,运⾏⼀切正常。
执⾏源代码
⾄此,我们的爬⾍也就写完了。废话也不多说了,直接上源码,希望我在记录的同时能对你有所帮助。
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import requests
from bs4 import BeautifulSoup
from prettytable import PrettyTable
class WeiboTop(object):
def __init__(self):
self.url = 's.weibo/top/summary'  # 微博热搜地址
def get_html(self):
"""获取⽹页内容"""
r = (self.url)
def analysis(self):
"""提取数据"""
results = []
htmls = _html()
soup = BeautifulSoup(htmls, 'lxml')
ranks = soup.find_all('td', class_='td-01 ranktop')
tags = soup.find_all('td', class_='td-02')
hots = soup.find_all('td', class_='td-03')
for rank, tag, hot in zip(ranks, tags, hots):
results.append(
[rank.string if rank else '',
tag.a.string,
tag.span.string if tag.span else 9999999,
hot.i.string if hot.i else ''])
return results
def __sort(self):
"""排序(倒序)"""
result = self.analysis()
return sorted(result, key=lambda x: int(x[2]), reverse=False)  # 反向排序
def show(self):
"""展⽰数据"""
tb = PrettyTable()
sorts_data = self.__sort()
tb.field_names = '排名,热点话题,阅读数,热点类型'.split(',')
for i in sorts_data:
tb.add_row(i)
print(tb)
if __name__ == "__main__":
wt = WeiboTop()
wt.show()
python的⽤处太多了,每⼀个要学习的⽅向,都挺多的,以后将不再把时间精⼒放在爬⾍上⾯。