爬虫实战(八):爬取表情包
一、 网站分析
1、 需求分析
在QQ斗图中,为什么有些人总有斗不完的图,今天,这里有了这个斗图小程序,终于可以告别斗图斗不赢的痛了。
这里,我们需要对发表情网站进行全站数据的爬取,让您拥有许许多多的表情包
2、 页面分析
通过抓包分析,我们发现,页面链接数据都在页面中,不是加载出来的数据,故,我们可以对网址直接发起请求,来进行数据的爬取
3、 链接分析
这里,我们对https://fabiaoqing.com/bqb/lists/type/hot.html进行链接的分析,
热图
https://fabiaoqing.com/bqb/lists/type/hot/page/1.html 第一页
https://fabiaoqing.com/bqb/lists/type/hot/page/2.html 第二页
https://fabiaoqing.com/bqb/lists/type/hot/page/n.html 第 n 页
情侣图
https://fabiaoqing.com/bqb/lists/type/liaomei/page/1.html
https://fabiaoqing.com/bqb/lists/type/liaomei/page/2.html
https://fabiaoqing.com/bqb/lists/type/liaomei/page/n.html
同时对于其他类型的表情包链接,也都是类似的
4、 详情页分析
通过抓包分析,我们发现,图片的链接也是保存在页面源码上面,同时,要注意,为了实现懒加载,该网站并没有一开始就把图片放在src属性上面,而是放在了data-original里面;但是,当我们把图片数据下载下来的时候,会发现,图片是尺寸有点小,那么,我们应该如何解决呢?
再点击一张图片,进入每张图片的详情页,可以发现里面有一张大的图,那我们是不是应该访问详情页来获取图片的下载链接呢?可不可以不这么麻烦呢?
我们首先来对比两张图的链接,发现两个链接之间就相差一个单词,那么我们就可以使用replace替换来直接获取大图,而不是通过访问详情页
http://tva3.sinaimg.cn/bmiddle/e16fc503gy1h3q1s3nl8tg20ge0geqv5.gif
http://tva3.sinaimg.cn/large/e16fc503gy1h3q1s3nl8tg20ge0geqv5.gif
5、 流程分析
- 使用for循环遍历每一种链接
- 获取每一类表情包的链接
- 解析每一类表情包里面的每一个表情包
二、 编写代码
1、 解析页数
import requests, os, re # 导包
from lxml import etree # 这次使用xpath解析数据
from fake_useragent import UserAgent # 随机请求头
if not os.path.exists("./表情包"):
os.mkdir("./表情包")
add_url = "https://fabiaoqing.com" # 用来拼接表情包的url
# 我们先准备好一个基础的url列表,当然这个也可以使用爬虫获取
base_urls = [
"https://fabiaoqing.com/bqb/lists/type/hot/page/%d.html",
"https://fabiaoqing.com/bqb/lists/type/liaomei/page/%d.html",
"https://fabiaoqing.com/bqb/lists/type/qunliao/page/%d.html",
"https://fabiaoqing.com/bqb/lists/type/doutu/page/%d.html"
"https://fabiaoqing.com/bqb/lists/type/duiren/page/%d.html",
"https://fabiaoqing.com/bqb/lists/type/emoji/page/%d.html"
]
headers = {
"user-agent": UserAgent().random,
}
def get_num(url):
"""解析到每一大类表情包有多少页"""
resp = requests.get(url, headers=headers)
resp.encoding = resp.apparent_encoding
html = etree.HTML(resp.text)
temp = html.xpath('//*[@id="mobilepage"]/text()')[0] # 定位到存放页数的地方
num = int(re.search("\d+", temp).group()) # 正则匹配数字
return num # 返回结果
page = get_num(base_urls[0] % 1)
2、 获取一类表情包
def get_eve_express(page_url):
resp = requests.get(page_url, headers=headers)
resp.encoding = resp.apparent_encoding
html = etree.HTML(resp.text)
a = html.xpath('//*[@id="bqblist"]/a') # 获取到存放每一类图片的a标签链接
# 遍历a标签
for i in a:
href = i.xpath("./@href")[0]
href = add_url + href # url 拼接
title = i.xpath("./@title")[0]
dic = {
"href": href,
"title": title
}
# 这里调用解析并下载表情包的函数,下面,我们就随便取一个字典来测试
print(dic)
get_eve_express(base_urls[0] % 1)
3、 保存表情包
test_dic = {'href': 'https://fabiaoqing.com/bqb/detail/id/54885.html', 'title': '站岗小狗表情包 \u200b_斗图表情包(8个表情)'}
def get_down_url(dic):
"""下载并存储表情包"""
if not os.path.exists(f"./表情包/{dic['title']}"):
os.mkdir(f"./表情包/{dic['title']}")
resp = requests.get(dic['href'], headers=headers)
info = re.findall('<img class="bqbppdetail lazy" data-original="(?P<href>.*?)" src', resp.text)
for i in info:
# 把图片换成大图
i = i.replace("bmiddle", "large")
resp = requests.get(i)
name = i.split("/")[-1]
with open(f"./表情包/{dic['title']}/{name}", "wb") as f:
f.write(resp.content)
print(f"{dic['title']}系列表情包保存完成!")
get_down_url(test_dic)
三、 总代码
import requests, os, re # 导包
from lxml import etree # 这次使用xpath解析数据
from fake_useragent import UserAgent # 随机请求头
if not os.path.exists("./表情包"):
os.mkdir("./表情包")
add_url = "https://fabiaoqing.com" # 用来拼接表情包的url
# 我们先准备好一个基础的url列表,当然这个也可以使用爬虫获取
base_urls = [
"https://fabiaoqing.com/bqb/lists/type/hot/page/%d.html",
"https://fabiaoqing.com/bqb/lists/type/liaomei/page/%d.html",
"https://fabiaoqing.com/bqb/lists/type/qunliao/page/%d.html",
"https://fabiaoqing.com/bqb/lists/type/doutu/page/%d.html"
"https://fabiaoqing.com/bqb/lists/type/duiren/page/%d.html",
"https://fabiaoqing.com/bqb/lists/type/emoji/page/%d.html"
]
headers = {
"user-agent": UserAgent().random,
}
def get_num(url):
"""解析到每一大类表情包有多少页"""
resp = requests.get(url, headers=headers)
resp.encoding = resp.apparent_encoding
html = etree.HTML(resp.text)
temp = html.xpath('//*[@id="mobilepage"]/text()')[0] # 定位到存放页数的地方
num = int(re.search("\d+", temp).group()) # 正则匹配数字
return num # 返回结果
def get_down_url(dic):
"""下载并存储表情包"""
if not os.path.exists(f"./表情包/{dic['title']}"):
os.mkdir(f"./表情包/{dic['title']}")
resp = requests.get(dic['href'], headers=headers)
info = re.findall('<img class="bqbppdetail lazy" data-original="(?P<href>.*?)" src', resp.text)
for i in info:
# 把图片换成大图
i = i.replace("bmiddle", "large")
resp = requests.get(i)
name = i.split("/")[-1]
with open(f"./表情包/{dic['title']}/{name}", "wb") as f:
f.write(resp.content)
print(f"{dic['title']}系列表情包保存完成!")
def get_eve_express(page_url):
resp = requests.get(page_url, headers=headers)
resp.encoding = resp.apparent_encoding
html = etree.HTML(resp.text)
a = html.xpath('//*[@id="bqblist"]/a') # 获取到存放每一类图片的a标签链接
# 遍历a标签
for i in a:
href = i.xpath("./@href")[0]
href = add_url + href # url 拼接
title = i.xpath("./@title")[0]
dic = {
"href": href,
"title": title
}
# 这里调用解析并下载表情包的函数,下面,我们就随便取一个字典来测试
# 下载表情包
get_down_url(dic)
def main():
for i in base_urls:
num = get_num(i % 1) # 获取到页数,再来一次for循环遍历
for j in range(1, num + 1):
get_eve_express(i % j) # 下载图片
if __name__ == "__main__":
main()