python爬虫实战—爬取大众点评评论(加密字体)

1.首先打开一个店铺找到评论

很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:101677771

2.分析网页

查看到下面有些字体经过加密处理 刷新页面会发现 每一次加密的字体是不一样的

3.发送请求获取数据

查看网页源代码 查看所有css 发现这个css就是我们想要用的文件 那么现在我们就要用代码来获取到这个css文件的urlCookie自行更换
代码实现:

class DownComment:

    def __init__(self):
# 爬取数据cookie user—agent
self.headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6"
") AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36",
"Cookie": 'fspop=test; _lxsdk_cuid=1741e6d406ec8-07a55a88376aea-31657305-13c680-1741e6d406ec8; _lxsdk=1741e6d406ec8-07a55a88376aea-31657305-13c680-1741e6d406ec8; _hc.v=686b52bb-73c6-234a-0599-c881b393882d.1598238311; Hm_lvt_602b80cf8079ae6591966cc70a3940e7=1598238354; cityid=838; default_ab=index%3AA%3A3; switchcityflashtoast=1; s_ViewType=10; ll=7fd06e815b796be3df069dec7836c3df; ua=dpuser_7474971098; ctu=4cc4b902d60a40f51447c2d6d386233260a8f2e43bf520fb73056aa472dfbb35; aburl=1; Hm_lvt_dbeeb675516927da776beeb1d9802bd4=1598270129; Hm_lpvt_dbeeb675516927da776beeb1d9802bd4=1598270129; cy=1; cye=shanghai; dper=627d6236bc87ce08b3d5c48661e5572f504bcf9938fee451ebd4566d8234bc5b1ad10791c702986d1398b6a838a4e550619d42c3d68d02b0f53cf4ed5c38702b47d41ef5f7e7d368892b8be8a46b2eb844582afbcc419e5e28df0a92c1df589e; uamo=17643530928; dplet=7731f44d071e7840935794d1a9ae35d4; Hm_lpvt_602b80cf8079ae6591966cc70a3940e7=1598342331; _lxsdk_s=1742497507a-072-c5-68e%7C%7C766'
}
# 爬取大众点评的url
self.url = None
# 页面返回的text
self.text = None
# css文件的内容
self.css_content = None
# css文件的url
self.css_url = None
# 取出的字体文件的内容
self.svg_content = None
# 用来存储每一个字的映射关系的列表
self.font_d_l = list()
# 用来存储坐标映射
self.position_l = list()
# 字体位置
self.position_list = list()
# 数据
self.data = list() def down_css(self):
"""
获取css文件
:return:
"""
# 请求返回的text
self.text = requests.get(self.url, headers=self.headers).text
# 使用xpath取出所有link中的链接
x = etree.HTML(self.text)
css_list = x.xpath('//link/@href')
self.css_url = 'https:' + str(re.findall('//s3plus\.meituan\.net.+?\.css', ' '.join(css_list))[0])

4.继续分析我们需要的东西

打开这个css文件 发现上一个页面加密的字体的类 在这个css文件中可以用查找到 后面有对应的坐标

5.尝试在css中找寻字体文件

查询css文件中 有没有我们想要的字体文件 command + f 或者 ctrl
+f 查询 发现文件中有三个字体文件 分别打开三个文件的url 发现只有一个字体映射文件是正确的

6.找出正确的字体文件

打开三个字体文件的url 发现正确的就是最多的 也就是最大的一个文件 我们不能凭着url来判断哪个字体文件更大 所以要访问 根据返回的数据 来判断正确的文件是哪个 接下来就要访问url来获取字体文件的内容 然后将最大的字体文件内容存储起来 方便替换

    def down_svg(self):
"""
下载字体文件
:return:
"""
# css请求返回的text
self.css_content = requests.get(self.css_url, headers=self.headers).text
# 使用正则取出
svg_list = re.findall(r"background-image: url\((.+?)\);", self.css_content)
svg_url = ["https:{}".format(svg) for svg in svg_list] # 下载最大的svg文件
length_d_l = list()
[length_d_l.append({"len": len(requests.get(svg).text), "content": requests.get(svg).text}) for svg in svg_url]
self.svg_content = str([x["content"] for x in length_d_l if x["len"] == max([i["len"] for i in length_d_l])][0])

7.由于是动态刷新 将网页数据保存到本地并分析 找到(x,y)和字体的映射关系

取出字体文件后可以在本地进行手动的查询 摸索文字对应关系 因为大众点评每一次刷新都是动态更改css或者svg文件内容 包括每次刷新加密的字都不同 所以将一个保存到本地 根据本地这一个固定的来尝试 尝试成功后动态获取 经过多次尝试 发现规律 两个数字第一个数字除以14
就是文字的下标
此图数字为-406 除以 14 下标 就是29 第二个数字就在两个y值中间 根据规律 匹配出所有文字的映射关系

!!!此段代码只是为了保存数据方便分析和爬取数据的代码无关 !!!

        with open("xx.html", "w")as f:
f.write(self.text)
with open('xx.css', "w") as f:
f.write(self.css_content)
with open("font.svg", "w") as f:
f.write(self.svg_content)

8.根据找到的规律 取出字体文件中所有字体 还有位置 存储到字典中

用正则在字体文件中取出数字的x值(即在本行的下标)y值用一个元组来存储 判断时 获取加密文字的坐标y值是否在元组两个值中间即可
取出所有的数据 保存到类中的字典
代码实现:

    def font_mapping(self):
"""
字体映射
:return:
"""
# 使用正则取出字
font_list = re.findall(r'<text x=".*" y="(.*)">(.+?)</text>', self.svg_content)
# 循环并将映射添加到列表中
for num, i in enumerate(font_list):
for x, v in enumerate(i[1]):
self.font_d_l.append({
"value": v,
"x": x,
"y": (int(font_list[num - 1][0]) if font_list[num - 1][0] != '2495' else 0, int(i[0]))
})

存储后的字典格式为 value值为字体内容 x为下标 y值为一个元组 用来存储在哪两个数字之间

9.现在开始获取所有css文件中的类对应的坐标

依旧使用正则来取出所有的数据 查询到的数据 再存储到类中的一个字典
代码实现:

    def position_mapping(self):
'''
位置映射
:return:
'''
all_ = re.findall("\.(.+?){background:-(.+?)\.0px -(.+?)\.0px;}", self.css_content)
[self.position_l.append({
"class": i[0],
"x": i[1],
"y": i[2],
}) for i in all_]

字典的格式为:

10.取出所有加密的字

现在取出网页中被加密的字体的class属性 使用xpath取出就可以
代码实现:

    def all_font_position(self):
"""
所有字体位置
:return:
"""
x = etree.HTML(self.text)
self.position_list = x.xpath('//svgmtsi/@class')

11.解密文字

因为现在已经取出了两个字典 一个有加密字体的class属性还有字体的x,y的值 另一个字典中有这个加密字体对应的文字 刚刚我们也取出来所有被加密文字的class属性 只需要循环判断 取出对应的字就可以来
代码实现:

    def find_font(self, x, y):
'''
查询具体字体
:param x:
:param y:
:return:
'''
# 根据坐标返回对应的字体
new_x = int(x) / 14
for i in self.font_d_l:
if int(i.get("x")) == int(new_x) and i.get('y')[0] < int(y) < i.get('y')[1]:
return i.get('value')

12.替换所有加密文字为解密后文字

将原来保存的这个网页的text内容中加密的文字 替换为正常的文字
代码实现:
这段代码在最后的运行方法中 就是主方法中

        str_text = str(self.text)
for position in self.position_list:
for x in self.position_l:
if x.get("class") == position:
str_text = str_text.replace('<svgmtsi class="{}"></svgmtsi>'.format(position),
str(self.find_font(x.get('x'), x.get('y')))).replace(" ",
'').replace(
" ", '')

13.获取数据

最难的加密已经弄出来了 现在就是一个简单的取数据就可以了 因为大众点评的长评论和短评论存储的xpath不同 所以需要一个小判断 直接看代码吧
代码实现:

  def get_data(self, str_text):
x = etree.HTML(str_text)
# 取出所以li标签
li = x.xpath('//div[@class="reviews-items"]/ul/li')
print(len(li))
for l in li:
# 定义一个字典用来存储数据
item = dict()
# 口味评分
flavor = l.xpath("./div/div/span/span[1]/text()")
# 环境评分
ambient = l.xpath("./div/div/span/span[2]/text()")
# 服务评分
service = l.xpath("./div/div/span/span[3]/text()")
# 人均价格
price = l.xpath("./div/div/span/span[4]/text()")
# 发布时间
times = l.xpath("./div[@class='main-review']/div/span[@class='time']/text()")
# 短评论
s_comment = l.xpath("div[@class='main-review']/div[@class='review-words']")
# 长评论
l_comment = l.xpath("div[@class='main-review']//div[@class='review-words Hide']")
# 存储到字典中
item["flavor"] = str(flavor[0]).replace('\n', '').replace(' ', '') if flavor else "暂无"
item["ambient"] = str(ambient[0]).replace('\n', '').replace(' ', '') if ambient else "暂无"
item["service"] = str(service[0]).replace('\n', '').replace(' ', '') if service else "暂无"
item["price"] = str(price[0]).replace('\n', '').replace(' ', '') if price else "暂无"
item["time"] = str(times[0]).replace('\n', '').replace(' ', '') if times else "暂无"
# 判断此条评论为长评还是短评 然后存储到字典
if l_comment:
l_str = html.unescape((etree.tostring(l_comment[0]).decode()))
l_com = re.findall('<div class="review-words Hide">(.+?)<div class="less-words">', l_str,
re.DOTALL)[0]
item["comment"] = l_com.replace('\n', '').replace(' ', '').replace('\t', '')
elif s_comment:
s_str = html.unescape((etree.tostring(s_comment[0]).decode()))
s_com = re.findall('<div class="review-words">(.+?)</div>', s_str, re.DOTALL)[0]
item["comment"] = s_com.replace('\n', '').replace(' ', '').replace('\t', '')
else:
item["comment"] = "该用户没有填写评论..."
# 类中的列表 来存储保存后的字典
self.data.append(item)

14.保存数据到csv文件中

代码实现:

    def save(self):
"""
保存数据为csv文件
:return:
"""
pandas.DataFrame(self.data,
columns=["flavor", "ambient", "service", "price", "time", "comment"]).to_csv(
'data.csv')

15.写一个调用所有方法的主方法

代码实现:

    def run(self, url):
self.url = url
# 获取css
self.down_css()
# 获取字体文件
self.down_svg()
# 添加字体映射
self.font_mapping()
# 添加位置映射
self.position_mapping()
# 获取所有加密字体位置
self.all_font_position()
# 查询对应字体 并替换
str_text = str(self.text)
for position in self.position_list:
for x in self.position_l:
if x.get("class") == position:
str_text = str_text.replace('<svgmtsi class="{}"></svgmtsi>'.format(position),str(self.find_font(x.get('x'),x.get('y')))).replace(" ",'').replace(" ", '')
# 获取数据
self.get_data(str_text)
# 保存文件
self.save()
# 控制台打印数据
pprint(self.data)

16.运行代码

代码如下:

def main():
# 创建爬虫对象
down_spider = DownComment()
# 爬取5页数据
for i in range(1, 2):
print('-----------当前为{}页---------------'.format(i))
url = "http://www.dianping.com/shop/k9oYRvTyiMk4HEdQ/review_all/p{}".format(i)
down_spider.run(url=url)

17.查看数据 保存数据

运行代码 查看数据即可 控制台打印以及保存到本地的csv文件 感谢你的观看 希望对你有所帮助
注:网站的反扒策略一直在变 有可能一小时前可以 有可能一小时后就不能使用了

python爬虫实战---爬取大众点评评论的更多相关文章

  1. Python爬虫之爬取慕课网课程评分

    BS是什么? BeautifulSoup是一个基于标签的文本解析工具.可以根据标签提取想要的内容,很适合处理html和xml这类语言文本.如果你希望了解更多关于BS的介绍和用法,请看Beautiful ...

  2. [Python爬虫] Selenium爬取新浪微博客户端用户信息、热点话题及评论 (上)

    转载自:http://blog.csdn.net/eastmount/article/details/51231852 一. 文章介绍 源码下载地址:http://download.csdn.net/ ...

  3. 第三百三十节,web爬虫讲解2—urllib库爬虫—实战爬取搜狗微信公众号—抓包软件安装Fiddler4讲解

    第三百三十节,web爬虫讲解2—urllib库爬虫—实战爬取搜狗微信公众号—抓包软件安装Fiddler4讲解 封装模块 #!/usr/bin/env python # -*- coding: utf- ...

  4. Python爬虫实战---抓取图书馆借阅信息

    Python爬虫实战---抓取图书馆借阅信息 原创作品,引用请表明出处:Python爬虫实战---抓取图书馆借阅信息 前段时间在图书馆借了很多书,借得多了就容易忘记每本书的应还日期,老是担心自己会违约 ...

  5. Python爬虫之爬取淘女郎照片示例详解

    这篇文章主要介绍了Python爬虫之爬取淘女郎照片示例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 本篇目标 抓取淘宝MM ...

  6. from appium import webdriver 使用python爬虫,批量爬取抖音app视频(requests+Fiddler+appium)

    使用python爬虫,批量爬取抖音app视频(requests+Fiddler+appium) - 北平吴彦祖 - 博客园 https://www.cnblogs.com/stevenshushu/p ...

  7. Python爬虫之爬取站内所有图片

    title date tags layut Python爬虫之爬取站内所有图片 2018-10-07 Python post 目标是 http://www.5442.com/meinv/ 如需在非li ...

  8. python爬取大众点评并写入mongodb数据库和redis数据库

    抓取大众点评首页左侧信息,如图: 我们要实现把中文名字都存到mongodb,而每个链接存入redis数据库. 因为将数据存到mongodb时每一个信息都会有一个对应的id,那样就方便我们存入redis ...

  9. 九 web爬虫讲解2—urllib库爬虫—实战爬取搜狗微信公众号—抓包软件安装Fiddler4讲解

    封装模块 #!/usr/bin/env python # -*- coding: utf-8 -*- import urllib from urllib import request import j ...

随机推荐

  1. Servlet容器启动过程

    参考:https://blog.csdn.net/fredaq/article/details/9366043 一.概念 所谓Servlet容器其实说白了是符合Servlet规范的Java web容器 ...

  2. 【BZOJ3307】雨天的尾巴 题解(树链剖分+树上差分)

    题目链接 题目大意:给定一颗含有$n$个结点的树,每次选择两个结点$x$和$y$,对从$x$到$y$的路径上发放一带$z$类型的物品.问完成所有操作后每个结点发放最多的时哪种物品. 普通的树链剖分貌似 ...

  3. 构建一个拥有sshd服务的docker镜像

    不直接描述结果,通过一个过程探究如何写一个 Dockerfile 一.环境 虚拟机CentOS7.4,Docker1.13.1 二.尝试步骤 1.下载基础镜像 docker pull alpine:3 ...

  4. .NETCore微服务探寻(三) - 远程过程调用(RPC)

    前言 一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目 ...

  5. 15、Java中级进阶 面向对象 继承

    1.何为面向对象 其本质是以建立模型体现出来的抽象思维过程和面向对象的方法(百度百科)是一种编程思维,也是一种思考问题的方式 如何建立面向对象的思维呢?1.先整体,再局部2.先抽象,再具体3.能做什么 ...

  6. CUDA线程、线程块、线程束、流多处理器、流处理器、网格概念的深入理解

    一.与CUDA相关的几个概念:thread,block,grid,warp,sp,sm. sp: 最基本的处理单元,streaming processor  最后具体的指令和任务都是在sp上处理的.G ...

  7. 【LeetCode/LintCode 题解】约瑟夫问题 · Joseph Problem

    n个人按顺序围成一圈(编号为1~n),从第1个人从1开始报数,报到k的人出列,相邻的下个人重新从1开始报数,报到k的人出列,重复这个过程,直到队伍中只有1个人为止,这就是约瑟夫问题.现在给定n和k,你 ...

  8. Setup Factory 9 打包安装程序过程中提示安装.net4.5、并启用md5加密算法

    1.在Before Installing选项卡中选择Ready to Install,点击Edit进入编辑窗口,切到最后一个选项卡Actions,把判断内容复制进去 -- These actions ...

  9. SourceTreet提交时显示remote: Incorrect username or password ( access token )(4种解决办法)

    引言 我因为第一次安装Sources Tree的时候进行破解时(跳过安装时的登录),因为操作失误造成了好多bug,导致Sources Tree不论提交,拉取,获取,都会报remote: Incorre ...

  10. 我的第一个程序Hello world

    //include:导入一个文件:stdio:标准输入输出库(std是一个标准库:i:input:o:output:):.h:头文件:<>:表示导入系统文件:“”表示导入系统文件 #inc ...