爬取微博的文案,你不可能一上来就把网上所有微博都爬下来。这就需要划定一个范围。比如说,某一账号下面所有的微博。
https://weibo.com/
这个地址据说比较难爬,会有反爬的措施,我直接放弃了。
https://m.weibo.cn/
这个地址是手机端的,感觉还可以,就是文案好像只能爬2000条左右,后来我发现下面那个能爬好多,就不用了。
https://weibo.cn/
这个是一个原始的3g版本微博,除了难看点,基本上可以满足爬取账号下所有微博的要求,当然,删掉了的肯定是没了。
爬谁好呢。我打算研究一下正能量的官媒。人民日报、央视新闻、新华网、人民网、新华视点、新华社中国网事、中国之声。这几个影响力好像比较大。就先选人民日报吧。他的地址是这样的。
https://weibo.cn/rmrb
访问不了的话,好像是要登陆一下,反正不登录你待会儿也爬不了,你现在登陆一下自己的账号就可以了。
看到这个页面,你会发现它还是比较原始的翻页的形式,不是那种下滑出现的懒加载。试着点击“下页”,看看地址栏的变化。它直接变成了这样。
https://weibo.cn/rmrb?page=2
很明显,这个地址后面只带一个参数,那就是第几页,然后点“上页”你就会发现首页其实是这样的。
https://weibo.cn/rmrb?page=1
所以,我们只要遍历page=1~n
就可以了。那么n
怎么获取呢。
首先你可以在顶上看到这个微博账号微博后面的方括号里有126595条微博,然后每页微博数是10条左右,那么大致上,n约等于12660。
但事实上,这个数量包含了已经被删除的微博,实际上在翻页的地方你可以看到,只有12658页。以这个为准就可以了。
那么怎么获取这个数呢。手动填写其实就可以满足了,自动的话,接下来对首页进行解析的时候可以顺带提一下。
现在我们就来定义一个函数的框架,很简单就叫做get_contents
其实就涉及到两个变量,一个是微博账号名name
,还有一个是要翻多少页page
,为了在出现错误,爬取中断的时候可以续上,我们再引入一个开始爬取的页数start
def get_contents(name,page,start=1):
print(name,page,start)
get_contents('rmrb',12658) # 这里start默认为1
get_contents('rmrb',12658,666)
然后,针对每一页,我们构造一个函数叫做get_contents_from_page
这里的变量其实就只有一个拼接好的地址url
就可以了。
def get_contents_from_page(url):
print(url)
get_contents_from_page('https://weibo.cn/rmrb?page=1')
于是我们可以把这两个函数拼接起来,形成我们完整的流程。
def get_contents(name,page,start=1):
for current_page in range(start,page+1):
print(current_page) # 为了追踪进度,出错重连,打印一下当前页码
url = 'https://weibo.cn/%s?page=%d' % (name,current_page)
get_contents_from_page(url)
现在get_contents_from_page
什么也没有做,只是打印了一下输入的地址,事实上,我们需要让他返回一个包含content_list
的结果。
在前面的章节中,我们已经学习了使用requests
模块进行页面请求,马上安排。
import requests
def get_contents_from_page(url):
r = requests.get(url)
print(r.text)
get_contents_from_page('https://weibo.cn/rmrb?page=1')
在这一步会遇到两个问题,一个是编码不对,出现乱码,还有一个就是要让你登陆,因为这个爬虫并没有用你的账号密码登陆过。
编码问题可以通过设置解决,而登陆问题需要你在https://weibo.cn/rmrb?page=1
这个页面,打开F12
,切换到Network
面板,然后F5
刷新,选择rmrb?page=1
,然后查看它的Headers
,在Request Headers
里面找到cookie: XXX
这一串。然后按这个格式填好。就可以获取正确的数据。
import requests
headers = {'cookie':'XXX'} # 按这个格式填好
def get_contents_from_page(url):
r = requests.get(url,headers=headers) # 这里处理登陆问题
r.encoding = 'utf-8' # 这里处理编码问题
print(r.text)
get_contents_from_page('https://weibo.cn/rmrb?page=1')
上面返回的数据是html
格式的,我们需要通过解析器来对这个文档进行解析,在前面的章节中,我们学习过BeautifulSoup
的使用,我们接下来就使用它对页面进行解析。而且根据对页面html
的观察,所有的微博文案都在id
以M_
开头的div
中。
import requests
from bs4 import BeautifulSoup
import re # 用到一点正则匹配
headers = {'cookie':'XXX'}
def get_contents_from_page(url):
r = requests.get(url,headers=headers)
r.encoding = 'utf-8'
soup = BeautifulSoup(r.text, 'html5lib') # 使用html5lib解析器,之前用的html.parser不太好
# 在这里我们其实就可以获取总页数
# info = soup.select('div.pa form div')[0].text
# page = re.split(r"[\/'页']",info)[-2]
# print(page)
contents = soup.select("div[id^='M_']")
for content in contents:
content_manage(content)
get_contents_from_page('https://weibo.cn/rmrb?page=1')
在上面的代码中,我们调用了一个content_manage
函数,对每一个content
进行处理,接下来,我们解析一些细节。
def content_manage(content):
temp = {
'bid': content['id'].split("_")[1],
'content': content.find("span",class_="ctt").text,
'attitudes_count': re.split(r"[\[\]]",content.find("a",string=re.compile(r"^赞\[")).text)[1],
'reposts_count': re.split(r"[\[\]]",content.find("a",string=re.compile(r"^转发\[")).text)[1],
'comments_count': re.split(r"[\[\]]",content.find("a",string=re.compile(r"^评论\[")).text)[1],
'created_at': content.find("span",class_="ct").text
}
# print(temp) # 这个临时的文档结构就不打印了吧 直接给它存到数据库里吧
save_content(temp)
这个形式的数据直接存在MongoDB
里会比较方便,在前面的章节中我们也学习过它的用法,于是可以这样。
import pymongo
myclient = pymongo.MongoClient("mongodb://XXX:[email protected]:27017/") # 登陆远程活本地的MongoDB
mydb = myclient["weibo_DB"] # 连接到存放微博的数据库db
def save_content(temp):
mycol = mydb["weibo_contents"] # 存放到内容的集合collection
flag = mycol.find_one({"bid":temp['bid']}) # 用一个简单的flag判断数据是否已经爬过了
if flag:
print('已存在') # 最终一次爬取可设为更新
else:
mycol.insert_one(temp)
如此一来,我们就不需要返回content_list
了,登陆数据库可视化软件就可以非常直观的看到一列列的数据。