Jos's Blog - Python
type: channel
link: https://blog.bbcking5.com/category/8/
items: 爬虫和自动化区别
items: Unicode和BNF介绍
items: EXCEL统计新方法

爬虫和自动化区别
type: item
date: 2024-07-29T20:35:17+08:00
description: 药监局可以查询每个药企的许可证编号。当我们如果想查找多家药企的许可证编号时候，就必须一条条查询，很麻烦。所以就需要想办法使用自动化程序来帮我们处理。后面当自动化程序运行起来后，发现这个网站是有防D（DDOS防御）的。而且频率限制的相当低。通常这种有两个解决办法。拉长每条数据爬取间隔，这样显然会让爬取数据的效率大大降低。通过动态代理IP来实现绕过防D检测，这样效率会非常高，效率无上限。但是要找到好用干净的IP还是比较难的。我在接下来测试时候，还交了40元学费后发现这些地址全部被药监局封了。白瞎了这40块钱。声明：本文章中所有内容仅供学习交流，抓包内容、敏感网址、数据接口均已做脱敏处理，严禁用于商业用途和非法用途，否则由此产生的一切后果均与作者无关，若有侵权，请联系我立即删除！什么是爬虫接触到现在，也许很多人眼里，爬虫就是获取网页数据的。自然也把实现这一目标的都归为爬虫。这么理解也没问题。那实现这一目的的有哪些方式呢？通过request请求直接发送请求获取response响应结果。特点效率高，难度高。（单子价格高，通常一个网页的爬虫通过此方式做出来，价格在几百到上万不等）自动化测试工具selenium、drissionpage 实现自动对浏览器的操作。特点效率慢，难度低。按我理解request才是真正的爬虫（直接交互数据），而后者selenium、drissionpage只是自动化测试工具。网站分析查看请求包打开浏览器后点击F12调试，再刷新下网页就能够看到所有的http请求。如上图，刚调试就遇到了两个问题：无限被Debug，正常刚打开调试不会进入Debug。后来关闭Debug，点击左侧三角箭头继续运行才加载出来查询结果。发生卡死现象，当想把一个个改成跳过Debug，可能触发了什么逻辑，直接网页卡死。后来也是按如上操作才出现了下面的请求结构。接下去我们来分析一下。网页上其实一个选择药企类型，一个是输入药企名称。然后点击查询按钮返回结果。正常的开发逻辑比较像上图的请求。同时我们看到药企的类型和名称全部是加密的，在header中还有sign签名。需要分析三块地方的的加密方法甚至更多。再加上无限Debug。对我爬虫初学者来说的确有点棘手，所以对于这种效率要求不高的情况下，使用自动化测试工具是个不错的选择。自动化测试工具当我使用selenium来访问药监局网站时候发现无法打开。为什么手动可以打开，用selenium无法打开？在我们手动直接访问、selenium、drissionpage访问有什么区别呢？访问https://bot.sannysoft.com/测试看下。手动直接访问浏览器特征全部通过。selenium会被检测到webdriver属性。测试药监局网站时候，由于被检测到webdriver属性，则直接显示白屏。from selenium import webdriver import time driver = webdriver.Chrome() driver.get("https://bot.sannysoft.com/") time.sleep(60) driver.quit()drissionpage和手动访问完全一致 ，浏览器特征全部通过。import time from DrissionPage import ChromiumPage page = ChromiumPage() page.get("https://bot.sannysoft.com/") time.sleep(60) page.quit()编写代码自动化测试工具本质还是模拟浏览器中点击输入等等操作。最常见的无非就是点击、输入、新建和切换标签页。想具体了解可以看drissonpage官方文档。下面就以官网文档来演示，如何把这些操作，通过代码来实现。准备工作安装Python V3.10以上版本pip安装软件包 pip install drissionpage安装chrome浏览器打开网页将上面的page.get("https://bot.sannysoft.com/") 网址替换为https://www.drissionpage.cn/ChromiumPage/tab此代码运行后就是打开网页的操作。定位元素通常元素定位有三个方式，一种是通过html元素选择器来定位，第二种种则是通过元素标签路径来定位，第三种元素标签来定位。如上图，我们要定位到右上角搜索框，那就在搜索框位置右键-->检查。弹出调试控制台，直接会到达该元素所在位置。其元素class选择器名称为DocSearch-Button-Placeholder，且搜索后该页面只有一个。（id选择器全局唯一，class选择器是有可能名称重复的，所以需要搜索确认下是否只有一个）。而sapn、div、butto…

Unicode和BNF介绍
type: item
date: 2024-06-21T22:02:00+08:00
description: 日常平台账号的开通是我上班内容之一。记得之前有人抱怨说，为啥给我的密码不对啊。当然不可能是我开错，因为一个开账号的过程简直要把人逼疯，我就说我这边的过程部分（1、从工单系统把账号需求填入表格记录后续用于迎检。 2、打开堡垒机输入账号密码验证码 3、打开平台页面登录 4、创建对应账号、授权、分组 5、复制出初始密码回填表格记录 6、编辑邮件反馈对应人员 7、工单系统反馈）。整整7步，其中最费时间的是3、4、5步骤随着账号数量，这是随账号数量线性上升的工作量。所以我肯定用脚本去解决，当然不可能是我开错或者复制错。那这个问题到底怎么来的呢，会是用户输错么？下面我们就探究一下原因。Unicode编码简介在计算机初期只有ASCII码，最多只有8位，只能够表示256个字符，除了容纳英文字符和几个简单的符号无法容纳更多。随着各国开始使用计算机，为了融入各国的文字。就诞生出了很多编码，如中国用的GBK编码。但是这就引来另一个问题，这些编码在传输的时候两边如果编码不同也没做对应转换的话，那到对端很可能变成真正的天书。所以为解决这个问题就有了Unicode国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。其中UTF-8可变长（使用英文只需要1字节，使用特殊字符需要2字节或者3字节等）的编码就是Unicode编码的实现方式。数据库中经常见到的utf8mb4也是指uft8 most byte 4，最高到4字节，mb3则是最高到3字节。对应如下表。Unicode符号范围 (十六进制)UTF-8编码方式 （二进制）0000 0000-0000 007F0xxxxxxx0000 0080-0000 07FF110xxxxx 10xxxxxx0000 0800-0000 FFFF1110xxxx 10xxxxxx 10xxxxxx0001 0000-0010 FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx测试测试之前我们看一下a = 'Αpple' ，b = 'Apple'，其中a和b是一样的吧。下面我们实际看一下子！>>> a = 'Αpple' >>> b = 'Apple' >>> print(a==b) False >>> bytes(a,'UTF-8').hex() 'ce9170706c65' >>> bytes(b,'UTF-8').hex() #后面的数字基本一样，那问题基本是出在第一个A上。 '4170706c65' >>> hex(ord('Α')) '0x391' >>> hex(ord('A')) #将单个字符转成10进制再转成16进制 '0x41'通过把两个字符串转成UTF8的编码再转成16进制看下，可以发现两个确实不是同一个A。所以当我们输入密码时候肯定是不对的。那为什么会造成这个问题呢？原因可能有些人电脑用的编码不一致，有些个别字符会导致差异。同样使用电脑过程中不要随意修改电脑系统的编码，尽量使用通用的utf8编码。当然除了这个情况，也有可能O和0的分不清1和小写的L 以及大写的i等，在手动输入密码时候也是经常会错。最后在声明一下，光在unicode编码中就存在很多易混淆的字符。BNF语法介绍在学习任何东西时候应当学会看官方文档，而在Python语法参考手册中1.2章节讲述的是后续章节用到的标注，用来对语法的解释。其实这里的标注是变种版的BNF语法标注，和标准版的稍微还有点区别，BNF语法其实有点像正则的用法。如下是BNF语法样例：if_stmt ::= "if" assignment_expression ":" suite ("elif" assignment_expression ":" suite)* ["else" ":" suite]::\= 表示“左侧是语法名称，右侧为语法规则的定义”例：exponent ::= "a"..."z" 意思为语法exponent是由单个小写a到z字母组成.| 表示“或者的意思”例：exponent ::= "a"|"z" 意思为语法exponent只能是a或者z.* 表示“对前一项重复0次或更多次”例：exponent ::= （"a"..."z"）* 意思为语法exponent是由0个（为空）或多个小写a到z字母组成.+ 表示“对前一项重复1次或更多次”例：exponent ::= （"a"..."z"）+ 意思为语法exponent是由1个（不为空）或多个小写a到z字母组成.[...] 表示“此项可选”例：exponent ::= "test"["a"|"z"] 意思为语法exponent可以是testa也可以是testz也可以是test.(...) 表示“分组”例：exponent ::= "test"（"a"|"z"） 意思为语法exp…

EXCEL统计新方法
type: item
date: 2024-05-30T00:12:00+08:00
description: 职场中，不管是运维还是开发还是项目经理或者财务，都可能存在茫茫多的excel去做一些统计处理。恐怖的是，可能统计方式随着需求变化也会经常修改修正。作为职员，接到统计需求可能很模糊，一周、当周，反正通常没有具体时间节点，或者因其他原因。随之变化会导致不断修改我们的统计方式。另外我自己的记性并不是很好，面对简单的统计还能记得住，当面对复杂点的统计，可能到下次就忘记之前怎么统计的了。在多方面的原因下，迫使我有动力去开发了一款尽可能的适应不同数据表格、不同统计需求的Python小程序。小程序介绍代码逻辑整套逻辑可以循环运行，意味着可以创建多份规则配置表的Sheet，来批量统计！相当省事！这是我的代码链接。目录介绍src : 源代码目录data_interaction : OS、GUI等逻辑代码目录excel_process : 处理Excel相关逻辑代码目录match_process : 对应统计规则配置表逻辑代码目录input : 统计规则配置表存放位置output : 统计后输出表存放位置使用说明1、环境准备提前安装Git工具，最新版即可提前安装Python环境，最好是V3.10以上版本2、下载小程序git clone https://github.com/wuxingyu090/excel_statistics.git # 也可直接访问网站下载V1.0.1 Releas压缩包 cd excel_statistics/ # 进入小程序目录下 pip install -r requirements.txt # 安装依赖包3、准备需要统计的Excel数据表格将数据文件放置excel_statistics目录下4、规则配置在input目录下的config-keycount.xlsx 即为规则配置表。其中每个Sheet(除说明Sheet)，都是单独一套规则配置策略。Sheet名称可自定义，但需要与main.py 文件中rule_table_list列表数据同时修改成自定义名称，才能执行程序。（因为考虑到可能有存在未配置完成的规则配置策略无需运行的情况）后续这个可能会做成Gui进行选择。如下配置样例：count_nametablesheetl1_fieldl1_matchl2_fieldl2_matchl3_fieldl3_matchl4_fieldl4_matchl5_fieldl5_matchTEST1故障告警模板信息2172621.xlsx告警单列表故障发生时间2021-04-26 TEST2故障告警模板信息2172621.xlsx告警单列表故障发生时间2021-04-26故障级别Z2故障主题(必填)广州百科云A_X86_天河MIX故障主题(必填)半双工模式 ASO3故障告警模板信息2172621.xlsx告警单列表故障发生时间%H,22-08故障级别=,Z2故障主题(必填)广州百科云A_X86_天河MIX故障主题(必填)['ecs-yaochi.EcsGrandcanalDashboard服务提供异常','实例切换'] ADB4故障告警模板信息2172621.xlsx告警单列表故障发生时间%H,22-08故障级别=,Z1故障主题(必填)广州百科云A_X86_天河MIX故障主题(必填)Cgroup挂载检查 Count_name列：统计名称可自定义，相同规则配置sheet中，每个Count_name名称不可相同。Table列：填入放置excel_statistics目录下数据表格，如有多份数据表格，则填写对应不同的表名。可从多份数据表中进行统计。sheet列：填入对应表格中需要统计数据的Sheet名称l?_field：第几层级的字段名，填入需要统计数据的Sheet中的字段l?_match：第几层级的匹配，填入匹配规则。列表和字符串默认使用模糊匹配，带有'>,','<,','<>,','=,','%D,','%H,','%MI,'此类前缀表达式会进入对应规则匹配。如上l?_field 和 l?_match 样例规则配置表格中只到了l10 。（我感觉应该够了，不够可往后顺延）# main.py 文件 def run(show): rule_table_list = ['count_rule', 'count_rule1', 'count_rule2'] #上面右侧列表中count_runle* 替换成对应规则配置表中自定义sheet名称 config_keycount = 'config-keycount' for rule_table in rule_table_list: chart_product(config_keycount, rule_table) if show: show_chart(rule_table) else: pa…