记得半个月以前的一晚,媳妇跟jb说,你看,苍老师发了条微博,内容为69,后来微博官方关闭了该条微博的评论功能~ css
虽然不知道69是什么意义,可是看评论,总感受是要开车了~html
打开连接:
https://weibo.com/u/1739928273?refer_flag=1001030101_&is_all=1#_rnd1530254292380
打开后就是苍老师的微博连接,能够看到,下面就是苍老师发布的微博拉,而内容就是咱们想要的东西~json
像微博这种大厂,想都不用想就知道解析html获取数据这条路是行不通的,那咱们F12 刷新下网页,看看请求? segmentfault
(5分钟过去了)尼玛,怎么一条微博动态都没看到,怎么获取?api
尝试屡次,依然找不到解决方案,欲想放弃,此时,三三同窗说,用wap版,微博有接口获取!!!浏览器
就这样,转战手机版,手机版苍老师连接以下:https://m.weibo.cn/u/1739928273;
老规矩,F12刷新网页,而后把请求一条一条过,结果发现一个玩意:app
比起PC版,手机版终于看到有点相似数据的东西了,那咱们打开第一条看看~函数
那咱们点击headers,把request url拿出来分析下: 优化
https://m.weibo.cn/api/container/getIndex?type=uid&value=1739928273&containerid=1076031739928273
复制代码
解析这这个url,这url带有3个参数:ui
type=uid
value=1739928273
containerid=1076031739928273
复制代码
这3个参数,惟一能肯定的就是value,为何这么说?回头看看苍老师手机版的连接:https://m.weibo.cn/u/1739928273,由此得知,1739928273就是苍老师微博的ID,不信, 你随便改下试试,可能会跳到其余老师那呢~
这不,简单把最后2位73改为12,就变成另外一位美女了~
貌似跑题了,咳咳,刚刚说到哪~
嗯,知道这几个参数,没啥特别的,那咱们试试滑动下屏幕,往下拉,拉取更多的数据,最后使用上面的方式,获取url:
https://m.weibo.cn/api/container/getIndex?type=uid&value=1739928273&containerid=1076031739928273&page=3
复制代码
与上面的url不一样的是,这里多了个参数page=3,不用想都知道,这是表明第三页的意思了~
结果分析,若是是第二页,page=2,第一页的话,是不携带page参数,可是尝试把page=0跟page=1两个状况,返回的数据跟不携带page参数是一直的,因此后面就把首页当作是page=1的状况处理~
ok,如今知道了数据在哪里,翻页怎么弄,那咱们就看看请求头把~
这个东西对于咱们有影响吗?暂时看是没有的,从上图就能看到请求的内容跟携带的参数~
那咱们打开看看,下面这条连接是什么内容?
https://m.weibo.cn/api/container/getIndex?type=uid&value=1739928273&containerid=1076031739928273
复制代码
嗯,打开以后,是这样的,wtf??这是什么??
此时,赶忙看看苍老师的内容:
这个问题,以前在写urllib的时候也说明过:
URL只容许部分ASCLL(数字字母和部分符号),其余的字符(包括汉字)是不符合URL的标准,
因此URL须要对这些字符进行URL编码,URL编码的方式是把须要编码的字符转化为 %xx 的形式。
一般 URL 编码是基于 UTF-8 的,函数说明也说起到给予UTF-8进行encode~
复制代码
Ok,那就说,提取text的内容就好啦~那咱们先写个请求吧
# -*- coding:utf-8 -*-
import requests
url = "https://m.weibo.cn/api/container/getIndex"
#请求的url
headers = {
"Host": "m.weibo.cn",
"Referer": "https://m.weibo.cn/u/1739928273",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
"Accept":'application/json, text/plain, */*',
"X-Requested-With":"XMLHttpRequest",
}
#请求头
params = {
"type": "uid",
"value": "1739928273",
"containerid": "1076031739928273",
"page": "1"}
#请求携带的参数
res = requests.get(url,headers=headers,params=params).content
print(res)
复制代码
执行后,获得的结果是这样的:
https://m.weibo.cn/api/container/getIndex?type=uid&value=1739928273&containerid=1076031739928273&page=1
复制代码
接下来能够干吗?就能够写正则来匹配啦,先找data,而后找cards,而后再获取每一个cards下面的text;
若是真的如上面说的,立刻写噼里啪啦写正则,就有点冲动了,看下返回结果的格式,感受是否是像json?
"ok":1,"data":{"cardlistInfo":{"containerid":"1076031739928273","v_p":
复制代码
没错,这就是json,那咱们就能够换一种方式处理~
res = requests.get(url,headers=headers,params=params)
cards = res.json().get("data").get("cards")
#获取carads下的全部项
复制代码
获取的就是下面这个截图的全部cards项:
那咱们看看cards里面的内容,这是第一个:
嗯,有发现不一样了吗?对的,就是有多了个关注XXX的一项,可是这一项,可是这一项不是咱们要的,那怎么搞?
逐个逐个分析,会发现,正常的数据都有这么一项:
for card in cards:
if card.get("card_type") == 9:
text = card.get("mblog").get("text")
print(text)
复制代码
输出的结果以下:
回头看了下,并非代码的错,并且由于发布的内容有带图片或者表情~
这种状况过滤掉就行了~只须要文字~
pattern = re.compile(r"(.*?)<span.*>(.*?)")
text = re.sub(pattern,"",text)
复制代码
从上面能够看到问题例子以下,那咱们只须要把里面的内容都干掉就行了~
啊啊啊啊啊啊啊啊啊
<span class = "url-icon"><img alt = [允悲] src = "https://user-gold-cdn.xitu.io/2018/6/29/1644b1bf47628785?w=32&h=32&f=png&s=2591" style = "width:1em; height:1em;"/></span>
复制代码
结果以下:
这里有个不解之谜,就是会看到,会有换行,缘由是这样的:
以前在介绍urllib的时候说起有,urllib有一个quote的方法,函数说明说起到给予UTF-8进行encode;
import urllib
kw = urllib.request.quote("很紧张啊啊啊啊↵<s")
print(kw)
复制代码
输出的内容长这样的:
%E5%BE%88%E7%B4%A7%E5%BC%A0%E5%95%8A%E5%95%8A%E5%95%8A%E5%95%8A%E2%86%B5%3Cs
复制代码
那咱们把中文都去掉,只留↵看看?
%E2%86%B5
复制代码
获得的结果就是这样的,OK,那假如咱们把上面这串结果匹配成空格,是否是就能解决问题?
但实际尝试了下,是不行的,那咱们就把数据打出来:
啊啊啊啊啊啊啊啊啊
<s
复制代码
最后会发现%0A才是那个回车符
%8A%0A%3Cspan
复制代码
去掉以后,会发现字符的确不见了,并且的的确不会换行了,问题解决;
kw = urllib.request.quote(text)
old_kw = re.sub("%0A","",kw)
new_kw = urllib.request.unquote(old_kw)
复制代码
回到正题,按照上面的代码爬下来的东西,好像没啥问题,但认真一看,咦~
这里谁说老师下垂了?
这里,很明显是以前的正则有问题,那咱们从新折腾下正则,此处过程就不说了,很痛苦。。最后改为这样:
pattern = re.compile(r"<.*?>")
复制代码
意思就是把<>符号内的内容都去掉,得出的结果:
//@李太白的表哥:老师…你好像下垂了……
查看图片
复制代码
这里能够看到,查看图片也是多余的,那咱们也去掉,包括有一些是转发微博的,也都干掉吧,就成这样了~
pattern = re.compile(r"<.*?>|转发微博|查看图片")
复制代码
执行下,结果是这样了,看上去很好:
//@李太白的表哥:老师…你好像下垂了……
复制代码
ok,这个是一个页面的内容抓取,总体代码以下:
# -*- coding:utf-8 -*-
import requests
import re
import urllib
url = "https://m.weibo.cn/api/container/getIndex"
#请求的url
headers = {
"Host": "m.weibo.cn",
"Referer": "https://m.weibo.cn/u/1739928273",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
"Accept":'application/json, text/plain, */*',
"X-Requested-With":"XMLHttpRequest",
}
#请求头
params = {
"type": "uid",
"value": "1739928273",
"containerid": "1076031739928273",
"page": "1"}
#请求携带的参数
res = requests.get(url,headers=headers,params=params)
cards = res.json().get("data").get("cards")
#获取carads下的全部项
for card in cards:
if card.get("card_type") == 9:
text = card.get("mblog").get("text")
# kw = urllib.request.quote(text)
# old_kw = re.sub("%0A","",kw)
# new_kw = urllib.request.unquote(old_kw)
# %0A 这串数字对应的就是这个回车字符
pattern = re.compile(r"<.*?>|转发微博|查看图片")
#这里就是把<>符号内的都匹配出来
text = re.sub(pattern,"",text)
print(text)
复制代码
既然一页搞定了,那咱们要爬多页,怎么破?这个很简单啦,直接改page参数就好了
另外还遇到一个问题:
数据这多了,还发现这种东西~固然,也是正则兼容下就好了~
结果上面的处理,缝缝补补,最终代码以下:
# -*- coding:utf-8 -*-
import requests
import re
import urllib
import codecs
url = "https://m.weibo.cn/api/container/getIndex"
#请求的url
headers = {
"Host": "m.weibo.cn",
"Referer": "https://m.weibo.cn/u/1761379670",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
}
#请求头
params = {
"type": "uid",
"value": "{uid}",
"containerid": "{containerid}",
"page":"{page}"}
#请求携带的参数
def get_Data(uid="3303658163", containerid="1005053303658163"):
total = 3000 #打算爬取的页数,好比100页
content = [] #存放获取到的微博正文内容
page =1 #页码,从第一页开始算
last_length = 0 #上一个的内容长度,用于对比上一次的整体内容长度跟此次是否一致,若是一致,则认为没有新数据,中止脚本处理
for i in range(total):
params["page"] = str(page)
params['uid'] = uid
params['containerid'] = str(containerid)
res = requests.get(url, headers=headers, params=params)
print(res.json().get("data"))
cards = res.json().get("data").get("cards")
# 获取carads下的全部项
for card in cards:
if card.get("card_type") == 9:
text = card.get("mblog").get("text")
kw = urllib.request.quote(text)
old_kw = re.sub("%0A","",kw)
new_text = urllib.request.unquote(old_kw)
# %0A 这串数字对应的就是这个回车字符
pattern = re.compile(r"<.*?>|转发微博|查看图片|查看动图|>")
#这里就是把<>符号内的都匹配出来,正则规则
text = re.sub(pattern,"",new_text)
content.append(text)
page +=1
if (len(content) == last_length):
print("已经获取不到更多内容,脚本暂停处理")
break
else:
last_length = len(content)
print("抓取第{page}页,目前总共抓取了 {count} 条微博".format(page=page, count=len(content)))
with codecs.open('jb.txt', 'w', encoding='utf-8') as f:
f.write("\n".join(content))
if __name__ == '__main__':
get_Data("1761379670", "1005051761379670")
复制代码
功能介绍的话,一路看下来就很明朗了,一句话就是,解析json而已;
可能有同窗问,上面的代码如何使用?直接copy出来执行便可,若是想爬某人的信息,好比吉泽明步:
https://m.weibo.cn/u/2360092592?uid=2360092592&luicode=10000011&lfid=100103
type%3D1%26q%3D%E5%90%89%E6%B3%BD%E6%98%8E%E6%AD%A5
复制代码
打开她的手机版微博主页
最后的输出结果以下:
该脚本可能依赖于网页结果,一旦网页结构发生变化,该脚本即不适用,请了解~
尝试过20个左右的用户,都可数据,如遇到问题,请留言告知,谢谢~
本文感谢三三同窗的极力支持,不然如研究PC版,估计就凉了~
本文主要解析怎么爬取手机版的微博内容,主要原理是解析json,遇到有趣的问题有2个,第一是正则,想获取什么,把不须要的处理掉就行了,否则什么都()去作,太麻烦了~第二,微博的换行符,一开始还想着\n匹配处理,结果发现不行,后来换个角度,弄成编码的格式就发现问题了;
好了,本文到此,谢谢你们~