在 Python 中,一般情况下我们可能直接用自带的 logging 模块来记录日志,包括我之前的时候也是一样。在使用时我们需要配置一些 Handler、Formatter 来进行一些处理,比如把日志输出到不同的位置,或者设置一个不同的输出格式,或者设置日志分块和备份。但其实个人感觉 logging 用起来其实并不是那么好用,其实主要还是配置较为繁琐。
常见使用
首先看看 logging 常见的解决方案吧,我一般会配置输出到文件、控制台和 Elasticsearch。输出到控制台就仅仅是方便直接查看的;输出到文件是方便直接存储,保留所有历史记录的备份;输出到 Elasticsearch,直接将 Elasticsearch 作为存储和分析的中心,使用 Kibana 可以非常方便地分析和查看运行情况。 所以在这里我基本会对 logging 做如下的封装写法:
1 |
import logging |
定义完了怎么使用呢?只需要使用定义的方法获取一个 logger,然后 log 对应的内容即可:
1 |
logger = get_logger() |
运行结果如下:
1 |
DEBUG - 2019-10-11 22:27:35,923 - process: 99490 - logger.py - __main__ - 81 - logger - this is a message |
我们看看这个定义的基本实现吧。首先这里一些常量是用来定义 logging 模块的一些基本属性的,比如 LOG_ENABLED 代表是否开启日志功能,LOG_TO_ES 代表是否将日志输出到 Elasticsearch,另外还有很多其他的日志基本配置,如 LOG_FORMAT 配置了日志每个条目输出的基本格式,另外还有一些连接的必要信息。这些变量可以和运行时的命令行或环境变量对接起来,可以方便地实现一些开关和配置的更换。 然后定义了这么一个 get_logger 方法,接收一个参数 name。首先该方法拿到 name 之后,会到全局的 loggers 变量里面查找,loggers 变量是一个全局字典,如果有已经声明过的 logger,直接将其获取返回即可,不用再将其二次初始化。如果 loggers 里面没有找到 name 对应的 logger,那就进行创建即可。创建 logger 之后,可以为其添加各种对应的 Handler,如输出到控制台就用 StreamHandler,输出到文件就用 FileHandler 或 RotatingFileHandler,输出到 Elasticsearch 就用 CMRESHandler,分别配置好对应的信息即可。 最后呢,将新建的 logger 保存到全局的 loggers 里面并返回即可,这样如果有同名的 logger 便可以直接查找 loggers 直接返回了。 在这里依赖了额外的输出到 Elasticsearch 的包,叫做 CMRESHandler,它可以支持将日志输出到 Elasticsearch 里面,如果要使用的话可以安装一下:
1 |
pip install CMRESHandler |
其 GitHub 地址是:https://github.com/cmanaha/python-elasticsearch-logger,具体的使用方式可以看看它的官方说明,如配置认证信息,配置 Index 分隔信息等等。 好,上面就是我之前常用的 logging 配置,通过如上的配置,我就可以实现将 logging 输出到三个位置,并可以实现对应的效果。比如输出到 Elasticsearch 之后,我就可以非常方便地使用 Kibana 来查看当前运行情况,ERROR Log 的比例等等,如图所示:
也可以在它的基础上做更进一步的统计分析。
loguru
上面的实现方式已经是一个较为可行的配置方案了。然而,我还是会感觉到有些 Handler 配起来麻烦,尤其是新建一个项目的很多时候懒得去写一些配置。即使是不用上文的配置,用最基本的几行 logging 配置,像如下的通用配置:
1 |
import logging |
我也懒得去写,感觉并不是一个优雅的实现方式。 有需求就有动力啊,这不,就有人实现了这么一个库,叫做 loguru,可以将 log 的配置和使用更加简单和方便。 下面我们来看看它到底是怎么用的吧。
安装
首先,这个库的安装方式很简单,就用基本的 pip 安装即可,Python 3 版本的安装如下:
1 |
pip3 install loguru |
安装完毕之后,我们就可以在项目里使用这个 loguru 库了。
基本使用
那么这个库怎么来用呢?我们先用一个实例感受下:
1 |
from loguru import logger |
看到了吧,不需要配置什么东西,直接引入一个 logger,然后调用其 debug 方法即可。 在 loguru 里面有且仅有一个主要对象,那就是 logger,loguru 里面有且仅有一个 logger,而且它已经被提前配置了一些基础信息,比如比较友好的格式化、文本颜色信息等等。 上面的代码运行结果如下:
1 |
2019-10-13 22:46:12.367 | DEBUG | __main__:<module>:4 - this is a debug message |
可以看到其默认的输出格式是上面的内容,有时间、级别、模块名、行号以及日志信息,不需要手动创建 logger,直接使用即可,另外其输出还是彩色的,看起来会更加友好。 以上的日志信息是直接输出到控制台的,并没有输出到其他的地方,如果想要输出到其他的位置,比如存为文件,我们只需要使用一行代码声明即可。 例如将结果同时输出到一个 runtime.log 文件里面,可以这么写:
1 |
from loguru import logger |
很简单吧,我们也不需要再声明一个 FileHandler 了,就一行 add 语句搞定,运行之后会发现目录下 runtime.log 里面同样出现了刚刚控制台输出的 DEBUG 信息。 上面就是一些基本的使用,但这还远远不够,下面我们来详细了解下它的一些功能模块。
详细使用
既然是日志,那么最常见的就是输出到文件了。loguru 对输出到文件的配置有非常强大的支持,比如支持输出到多个文件,分级别分别输出,过大创建新文件,过久自动删除等等。 下面我们分别看看这些怎样来实现,这里基本上就是 add 方法的使用介绍。因为这个 add 方法就相当于给 logger 添加了一个 Handler,它给我们暴露了许多参数来实现 Handler 的配置,下面我们来详细介绍下。 首先看看它的方法定义吧:
1 |
def add( |
看看它的源代码,它支持这么多的参数,如 level、format、filter、color 等等,另外我们还注意到它有个非常重要的参数 sink,我们看看官方文档:https://loguru.readthedocs.io/en/stable/api/logger.html#sink,可以了解到通过 sink 我们可以传入多种不同的数据结构,汇总如下:
- sink 可以传入一个 file 对象,例如
sys.stderr或者open('file.log', 'w')都可以。 - sink 可以直接传入一个
str字符串或者pathlib.Path对象,其实就是代表文件路径的,如果识别到是这种类型,它会自动创建对应路径的日志文件并将日志输出进去。 - sink 可以是一个方法,可以自行定义输出实现。
- sink 可以是一个 logging 模块的 Handler,比如 FileHandler、StreamHandler 等等,或者上文中我们提到的 CMRESHandler 照样也是可以的,这样就可以实现自定义 Handler 的配置。
- sink 还可以是一个自定义的类,具体的实现规范可以参见官方文档。
所以说,刚才我们所演示的输出到文件,仅仅给它传了一个 str 字符串路径,他就给我们创建了一个日志文件,就是这个原理。
基本参数
下面我们再了解下它的其他参数,例如 format、filter、level 等等。 其实它们的概念和格式和 logging 模块都是基本一样的了,例如这里使用 format、filter、level 来规定输出的格式:
1 |
logger.add('runtime.log', format="{time} {level} {message}", filter="my_module", level="INFO") |
删除 sink
另外添加 sink 之后我们也可以对其进行删除,相当于重新刷新并写入新的内容。 删除的时候根据刚刚 add 方法返回的 id 进行删除即可,看下面的例子:
1 |
from loguru import logger |
看这里,我们首先 add 了一个 sink,然后获取它的返回值,赋值为 trace。随后输出了一条日志,然后将 trace 变量传给 remove 方法,再次输出一条日志,看看结果是怎样的。 控制台输出如下:
1 |
2019-10-13 23:18:26.469 | DEBUG | __main__:<module>:4 - this is a debug message |
日志文件 runtime.log 内容如下:
1 |
2019-10-13 23:18:26.469 | DEBUG | __main__:<module>:4 - this is a debug message |
可以发现,在调用 remove 方法之后,确实将历史 log 删除了。但实际上这并不是删除,只不过是将 sink 对象移除之后,在这之前的内容不会再输出到日志中。 这样我们就可以实现日志的刷新重新写入操作。
rotation 配置
用了 loguru 我们还可以非常方便地使用 rotation 配置,比如我们想一天输出一个日志文件,或者文件太大了自动分隔日志文件,我们可以直接使用 add 方法的 rotation 参数进行配置。 我们看看下面的例子:
1 |
logger.add('runtime_{time}.log', rotation="500 MB") |
通过这样的配置我们就可以实现每 500MB 存储一个文件,每个 log 文件过大就会新创建一个 log 文件。我们在配置 log 名字时加上了一个 time 占位符,这样在生成时可以自动将时间替换进去,生成一个文件名包含时间的 log 文件。 另外我们也可以使用 rotation 参数实现定时创建 log 文件,例如:
1 |
logger.add('runtime_{time}.log', rotation='00:00') |
这样就可以实现每天 0 点新创建一个 log 文件输出了。 另外我们也可以配置 log 文件的循环时间,比如每隔一周创建一个 log 文件,写法如下:
1 |
logger.add('runtime_{time}.log', rotation='1 week') |
这样我们就可以实现一周创建一个 log 文件了。
retention 配置
很多情况下,一些非常久远的 log 对我们来说并没有什么用处了,它白白占据了一些存储空间,不清除掉就会非常浪费。retention 这个参数可以配置日志的最长保留时间。 比如我们想要设置日志文件最长保留 10 天,可以这么来配置:
1 |
logger.add('runtime.log', retention='10 days') |
这样 log 文件里面就会保留最新 10 天的 log,妈妈再也不用担心 log 沉积的问题啦。
compression 配置
loguru 还可以配置文件的压缩格式,比如使用 zip 文件格式保存,示例如下:
1 |
logger.add('runtime.log', compression='zip') |
这样可以更加节省存储空间。
字符串格式化
loguru 在输出 log 的时候还提供了非常友好的字符串格式化功能,像这样:
1 |
logger.info('If you are using Python {}, prefer {feature} of course!', 3.6, feature='f-strings') |
这样在添加参数就非常方便了。
Traceback 记录
在很多情况下,如果遇到运行错误,而我们在打印输出 log 的时候万一不小心没有配置好 Traceback 的输出,很有可能我们就没法追踪错误所在了。 但用了 loguru 之后,我们用它提供的装饰器就可以直接进行 Traceback 的记录,类似这样的配置即可:
1 |
@logger.catch |
我们做个测试,我们在调用时三个参数都传入 0,直接引发除以 0 的错误,看看会出现什么情况:
1 |
my_function(0, 0, 0) |
运行完毕之后,可以发现 log 里面就出现了 Traceback 信息,而且给我们输出了当时的变量值,真的是不能再赞了!结果如下:
1 |
\> File "run.py", line 15, in <module> |
因此,用 loguru 可以非常方便地实现日志追踪,debug 效率可能要高上十倍了? 另外 loguru 还有很多很多强大的功能,这里就不再一一展开讲解了,更多的内容大家可以看看 loguru 的官方文档详细了解一下:https://loguru.readthedocs.io/en/stable/index.html。 看完之后,是时候把自己的 logging 模块替换成 loguru 啦!





这次将详细目录呈现给大家。请大家先阅读《Python3 反爬虫原理与绕过实战》的内容提要
作者韦世东是资深爬虫工程师,2019年华为云认证云享专家、掘金社区优秀作者、GitChat认证作者、搜狐产品技术约稿作者、夜幕团队成员。拥有七年互联网从业经验,擅长反爬虫的设计和绕过技巧。

这时候,如果我们能有一个客户端,即 Window 上的 exe 程序或 Mac 上的 app 应用程序,它们的名字就叫做 GitHub、微信公众平台等等,打开之后只单独负责呈现 GitHub、微信公众号的内容,我们就可以免去在浏览器中来回寻找站点和切换站点的麻烦。 甚至说,在 Windows 上我们可以直接把这个应用放在桌面或把它 Pin 到任务栏上, Mac 上我们可以直接将它固定到 Dock 栏上,这样一键就打开了,省时省力。如果使用了快捷启动软件,比如 Wox (Windows)或 Alfred(Mac),直接输入 GitHub 或者微信公众平台,那就更方便唤出了,简直不要太方便。 而且,我个人感觉,用客户端软件比用网页更有一种「踏实感」,不知道大家会不会也有这种感觉。 所以,如果能将这些常用的或者重度依赖的网站转成客户端软件,那就再方便不过了。 比如我用的是 Mac,把 GitHub 转成客户端软件之后,我习惯性用 Alfred 呼出:
然后就打开了一个 GitHub.app:
然后把它固定到 Dock 栏上:
就仿佛拥有了一个 GitHub 的客户端,功能与网页一模一样,再也不用在浏览器里面切来切去。而且也不用担心版本更新的问题,因为它就是开了一个独立的网页,网页改版或者更新,内容就随着更新。 是不是很方便呢? 如果你觉得是,那就随着我来了解一下怎样实现吧。
怎样,不论是什么网页,就可以使用它来转换成一个客户端软件。 另外它支持三大操作系统,Windows、Linux、Mac,即用它可以将网页转成
这个名字有点奇怪,我们可以使用命令的一个选项即可控制生成的客户端的名称,添加一个 name 参数即可:
另外我们可以看到客户端的图标也自动生成了,这个图标怎么来的呢?这个是用的 nativefier 维护的 icons,恰好 GitHub 在它们的收录范围内,所以就用上了。这些 icons 也是一个公开的 Repository,链接为:
然后把图片使用下面的命令就可以自定义图标了:
好了,这就是基本的用法,其实大部分情况只需要这几个参数就够了,如果想了解功能大家可以参考官方的 API 文档:
于是,这篇《利用 GitHub 从零开始搭建一个博客》的文章就诞生了。
这样一个博客的架子就出来了,我们只用了三个命令就完成了。
这时候我们去 GitHub 上面看看 Hexo 上传了什么内容,打开之后可以看到 master 分支有了这样的内容:
仔细看看,这实际上是博客文件夹下面的 public 文件夹下的所有内容,Hexo 把编译之后的静态页面内容上传到 GitHub 的 master 分支上面去了。 这时候可能就有人有疑问了,那我博客的源码也想放到 GitHub 上面怎么办呢?其实很简单,新建一个其他的分支就好了,比如我这边就新建了一个 source 分支,代表博客源码的意思。 具体的添加过程就很简单了,参加如下命令:

另外还有几个可选项,比如:
将其放置到 themes/next/source/images/avatar.png 路径,然后在主题 _config.yml 文件下编辑 avatar 的配置,修改为正确的路径即可。
配置完成之后就会显示头像。
修改后的代码样式:
嗯,个人觉得整体看起来逼格高了不少。
可以看到在页面右上角显示了 GitHub 的图标,点击可以进去到 Repository 页面。
GitHub 授权登录之后就可以使用了,评论的内容会自动出现在 Issue 里面。
可以看到左侧导航也出现了标签,点击之后右侧会显示标签的列表。
下面有个 custom domain 的选项,输入你想自定义的域名地址,然后添加 CNAME 解析就好了。 另外下面还有一个 Enforce HTTPS 的选项,GitHub Pages 会在我们配置自定义域名之后自动帮我们配置 HTTPS 服务。刚配置完自定义域名的时候可能这个选项是不可用的,一段时间后等到其可以勾选了,直接勾选即可,这样整个博客就会变成 HTTPS 的协议的了。 另外有一个值得注意的地方,如果配置了自定义域名,在目前的情况下,每次部署的时候这个自定义域名的设置是会被自动清除的。所以为了避免这个情况,我们需要在项目目录下面新建一个 CNAME 文件,路径为 source/CNAME,内容就是自定义域名。 比如我就在 source 目录下新建了一个 CNAME 文件,内容为:


这时候,我想到了一个东西——Docker,它可以用来解决这个问题! 因为 Docker 容器被创建后,不管外界的网卡有多少个,容器内部的网卡都只会有一个Docker自己的虚拟网卡(容器间通信用的)和一个本地环回接口(不用管它),而且我们在容器内进行拨号操作时,产生的那个新的虚拟网卡也不会影响到外界或其他容器,这样的话,代理服务器就不需要指定网卡了,直接启动就能跑! 那么现在整个流程就跑通了,进入实际操作环节看看吧!
可以看到,如前文所述,现在有三个网卡,一个是 Docker 自己的、一个是本地环回接口(这个不用管)、一个是拨号产生的虚拟网卡。
文章在某个位置会渐变隐藏,同时浮现一个公众号的样子,需要扫码才能解锁。这时候读者扫码自动关注了公号,博客文章也自然而然地解锁,这样博客的读者就自然关注到公号上面来了。
好,既然隐藏了,那么下面就加个提示吧,把公众号的二维码先放上,然后把那个 Session ID 放上,提示用户关注公众号后发送这个 ID 就能解锁了,但这个 ID 又不能太长,多少呢?六位吧那就。 类似做成这样的样子:
好,那么这个 ID 怎么获取的呢? 刚才说了,从 Cookies 里面获取就行了,找那个能够标识 Session ID 的一个 Cookies 字段,然后摘取其值的其中几位就行了,摘取的位置也有讲究,前几位仿佛重复率很高的样子,后面几位几乎不重复,那就截取最后六位数字吧。 好,然后我就在博客里面加了这么一点 JavaScript 代码来实现这个 ID 的提取:
然后关注了公号,发送了代码:
发送完毕之后,大约一两秒之后,抬头看看博客,就是这个样子了:
这已经就完成了解锁和转化,读者可以全站永久解锁我的博客文章,我也增长了粉丝。 现在过一段时间就会有读者发来代码解锁,同时成为了我的粉丝,订阅号助手看到消息如下:
以上便是这个博客转化的思路分享和实现,大家也可以到我的博客体验一下,谢谢!




我们的目的就是它的正文、标题等内容。下面我们用 Readability 试一下,示例如下:
下面用一个实例来感受一下:
看看运行结果:
视频换脸技术大家应该早有耳闻,但这个软件有点意思,它抓住了几个点使得它一炮而红。 第一是这个软件的效果确实不错,我拿自己也做了实验,发现确实它渲染的一些结果几乎毫无违和感,毕竟这个软件核心拼的就是技术。 第二这个软件贴近于日常生活,我们可以把自己的照片上传,让我们真正成为视频里的主角。另外视频选材很有讲究,都是一些剪辑过的明星精彩镜头,这样我们生成的视频镜头会让我们有变成明星的感觉,非常有代入感。
一般来说一张脸会用 68 个点来标记出来,每识别的模型接收一张人脸图像,输出这 68 个点的坐标,这样我们就可以实现人脸定位了。 现在现成的模型也很多了,比如 dlib,opencv 等开源工具包可以直接拿来使用了,如果要更精准地话可以使用更复杂的卷积神经网络模型来实现,大家可以了解下相关论文。
这时候我自然而然想到,既然用的是 3D 结构光摄像头,那么如果用了 3D 打印技术把一个人的肖像打印出来,或者用一个非常逼真的蜡像来进行刷脸识别,能不能通过呢?我看了一些报道,发现不少案例的确通过了刷脸测试,比如解开了 iPhone 面部识别锁等等。但要通过 3D 打印技术来模拟一个人的肖像成本还是蛮高的,所以基本上也不太会有人来搞这些。 如果对此还心有余悸的话,支付宝还回应称,即便是真的被盗刷了,支付宝也会通过保险公司进行全额赔付。 所以基本上是不用担心其安全性的,尤其是 Zao 这个软件的出现是没有对刷脸支付的风险造成大的影响的,其就是增加了一个活体视频模拟的实现,对刷脸支付的安全性没有出现大的突破性威胁。
我们通过几个例子来看看 MySQL 与 MongoDB 的差异。 与 MySQL 数据库不同的是,MongoDB 不需要预先定义表和字段,这正是它灵活性的体现。MongoDB 可以拥有多个数据库,每个数据库可以拥有多个集合,每个集合可以存储多份文档,这种关系与 SQL 数据库中的“数据库、表、数据”相当。下图描述了 MongoDB 中数据库、集合和文档的关系:
描述节主点掉线,重新选举主节点的图
如果你觉得有学习 MongoDB 的需要,且这篇文章规划的内容是你想要的内容,那么请长按下方图片识别二维码,前往订阅文章吧! 
图 9-5 讯代理官网 有多种类别的代理可供选购,摘抄其官网的各类别代理介绍如下:
图 9-6 提取页面 比如在这里我的提取 API 为:
图 9-7 提取结果 接下来我们要做的就是解析这个 Json,然后将其放入我们的代理池中。 当然如果信赖讯代理的话也可以不做代理池筛选,直接使用,不过我个人还是推荐再使用代理池筛选一遍,提高可用几率。 根据上一节代理池的写法,我们只需要在 Crawler 中再加入一个 crawl 开头的方法即可。 方法实现如下:
图 9-8 阿布云官网 阿布云的代理主要分为两种,专业版和动态版,另外还有定制版,摘抄官网的介绍如下:
图 9-9 阿布云代理后台 可以发现整个代理的连接域名为 proxy.abuyun.com,端口为 9020,均是固定的,但是使用之后每次的 IP 都会更改,这其实就是利用了代理隧道实现。 其官网原理介绍如下:
图 9-1 代理池架构 代理池分为四个部分,获取模块、存储模块、检测模块、接口模块。
图 9-2 运行结果 以上是代理池的控制台输出,可以看到可用代理设置为 100,不可用代理分数减 1。 接下来我们再打开浏览器,当前配置了运行在 5555 端口,所以打开:
图 9-3 首页页面 再访问:
图 9-4 获取代理页面 所以后面我们只需要访问此接口即可获取一个随机可用代理,非常方便。 获取代理的代码如下:
图 8-24 验证码示例 鼠标滑动后的轨迹会以黄色的连线来标识,如图 8-25 所示:
图 8-25 滑动过程 我们可以访问新浪微博移动版登录页面就可以看到如上验证码,链接为:
图 8-26 C 型
图 8-27 Z 型
图 8-28 X 型 而同时我们发现同一种类型它的连线轨迹是相同的,唯一不同的就是连线的方向,如图 8-29、8-30 所示:
图 8-29 反向连线
图 8-30 正向连线 这两种验证码的连线轨迹是相同的,但是由于连线上面的指示箭头不同导致滑动的宫格顺序就有所不同。 所以要完全识别滑动宫格顺序的话就需要具体识别出箭头的朝向,而观察一下整个验证码箭头朝向一共可能有 8 种,而且会出现在不同的位置,如果要写一个箭头方向识别算法的话需要都考虑到不同箭头所在的位置,我们需要找出各个位置的箭头的像素点坐标,同时识别算法还需要计算其像素点变化规律,这个工作量就变得比较大。 这时我们可以考虑用模板匹配的方法,模板匹配的意思就是将一些识别目标提前保存下来并做好标记,称作模板,在这里我们就可以获取验证码图片并做好拖动顺序的标记当做模板。在匹配的时候来对比要新识别的目标和每一个模板哪个是匹配的,如果找到匹配的模板,则被匹配到的模板就和新识别的目标是相同的,这样就成功识别出了要新识别的目标了。模板匹配在图像识别中也是非常常用的一种方法,实现简单而且易用性好。 模板匹配方法如果要效果好的话,我们必须要收集到足够多的模板才可以,而对于微博宫格验证码来说,宫格就 4 个,验证码的样式最多就是 4 3 2 * 1 = 24 种,所以我们可以直接将所有模板都收集下来。 所以接下来我们需要考虑的就是用何种模板来进行匹配,是只匹配箭头还是匹配整个验证码全图呢?我们来权衡一下这两种方式的匹配精度和工作量:
图 8-31 获取结果 在这里我们只需要挑选出不同的 24 张验证码图片并命名保存就好了,名称可以直接取作宫格的滑动的顺序,如某张验证码图片如图 8-32 所示:
图 8-32 验证码示例 我们将其命名为 4132.png 即可,也就是代表滑动顺序为 4-1-3-2,按照这样的规则,我们将验证码整理为如下 24 张图,如图 8-33 所示:
图 8-33 整理结果 如上的 24 张图就是我们的模板,接下来我们在识别的时候只需要遍历模板进行匹配即可。
图 8-34 运行效果 鼠标会慢慢的从起始位置移动到终止位置,最后一个宫格松开之后便完成了验证码的识别。 至此,微博宫格验证码的识别就全部完成了。 识别完成之后验证码窗口会自动关闭,接下来直接点击登录按钮即可完成微博登录。
图 8-18 12306 验证码 我们需要直接点击图中符合要求的图,如果所有答案均正确才会验证成功,如果有一个答案错误,验证就会失败,这种验证码就可以称之为点触验证码。 另外还有一个专门提供点触验证码服务的站点,叫做 TouClick,其官方网站为:
图 8-19 验证码样式 和 12306 站点有相似之处,不过这次是点击图片中的文字,不是图片了,另外还有各种形形色色的点触验证码,其交互形式可能略有不同,但基本原理都是类似的。 接下来我们就来统一实现一下此类点触验证码的识别过程。
图 8-20 12306 验证码 如点击图中所有的漏斗,“漏斗”二字其实都经过变形、放缩、模糊处理了,如果要借助于前面我们讲的 OCR 技术来识别,识别的精准度会大打折扣,甚至得不到任何结果。第二点是图像的识别,我们需要将图像重新转化文字,可以借助于各种识图接口,可经我测试识别正确结果的准确率非常低,经常会出现匹配不正确或匹配不出结果的情况,而且图片本身的的清晰度也不够,所以识别难度会更大,更何况需要同时识别出八张图片的结果,且其中几个答案需要完全匹配正确才能验证通过,综合来看,此种方法基本是不可行的。 再拿 TouClick 来说,如图 8-21 所示:
图 8-21 验证码示例 我们需要从这幅图片中识别出植株二字,但是图片的背景或多或少会有干扰,导致 OCR 几乎不会识别出结果,有人会说,直接识别白色的文字不就好了吗?但是如果换一张验证码呢?如图 8-22 所示:
图 8-22 验证码示例 这张验证码图片的文字又变成了蓝色,而且还又有白色阴影,识别的难度又会大大增加。 那么此类验证码就没法解了吗?答案当然是有,靠什么?靠人。 靠人解决?那还要程序做什么?不要急,这里说的人并不是我们自己去解,在互联网上存在非常多的验证码服务平台,平台 7x24 小时提供验证码识别服务,一张图片几秒就会获得识别结果,准确率可达 90% 以上,但是就需要花点钱来购买服务了,毕竟平台都是需要盈利的,不过不用担心,识别一个验证码只需要几分钱。 在这里我个人比较推荐的一个平台是超级鹰,其官网为:
图 8-23 点选效果 最后我们需要做的就是点击提交验证的按钮等待验证通过,再点击登录按钮即可成功登录,后续实现在此不再赘述。 这样我们就借助于在线验证码平台完成了点触验证码的识别,此种方法也是一种通用方法,用此方法来识别 12306 等验证码也是完全相同的原理。
图 8-5 验证码示例
图 8-6 验证码示例 现在极验验证码已经更新到了 3.0 版本,截至 2017 年 7 月全球已有十六万家企业正在使用极验,每天服务响应超过四亿次,广泛应用于直播视频、金融服务、电子商务、游戏娱乐、政府企业等各大类型网站,下面是斗鱼、魅族的登录页面,可以看到其都对接了极验验证码,如图 8-7 和 8-8 所示:
图 8-8 魅族登录页面
图 8-9 验证按钮 此按钮为智能验证按钮,点击一下即可智能验证,一般来说如果是同一个 Session,一小段时间内第二次登录便会直接通过验证,如果智能识别不通过,则会弹出滑动验证窗口,我们便需要拖动滑块来拼合图像完成二步验证,如图 8-10 所示:
图 8-10 拖动示例 验证成功后验证按钮便会变成如下状态,如图 8-11 所示:
图 8-11 验证成功结果 接下来我们便可以进行表单提交了。 所以在这里我们要识别验证需要做的有三步:
图 8-12 缺口示例
图 8-13 缺口示例 可以看到缺口的四周边缘有明显的断裂边缘,而且边缘和边缘周围有明显的区别,我们可以实现一个边缘检测算法来找出缺口的位置。对于极验来说,我们可以利用和原图对比检测的方式来识别缺口的位置,因为在没有滑动滑块之前,缺口其实是没有呈现的,如图 8-14 所示:
图 8-14 初始状态 所以我们可以同时获取两张图片,设定一个对比阈值,然后遍历两张图片找出相同位置像素 RGB 差距超过此阈值的像素点位置,那么此位置就是缺口的位置。 第三步操作看似简单,但是其中的坑比较多,极验验证码增加了机器轨迹识别,匀速移动、随机速度移动等方法都是不行的,只有完全模拟人的移动轨迹才可以通过验证,而人的移动轨迹一般是先加速后减速的,这又涉及到物理学中加速度的相关问题,我们需要模拟这个过程才能成功。 有了基本的思路之后就让我们用程序来实现一下它的识别过程吧。
图 8-15 初始状态
图 8-16 后续状态 两张图片其实有两处明显不同的地方,一个就是待拼合的滑块,一个就是缺口,但是滑块的位置会出现在左边位置,缺口会出现在与滑块同一水平线的位置,所以缺口一般会在滑块的右侧,所以要寻找缺口的话,我们直接从滑块右侧寻找即可,所以在遍历的时候我们直接设置了遍历的起始横坐标为 60,也就是在滑块的右侧开始识别,这样识别出的结果就是缺口的位置了。 到现在为止,我们就可以获取缺口的位置了,剩下最后一步模拟拖动就可以完成验证了。
图 8-17 识别成功结果 最后,我们只需要将表单完善,模拟点击登录按钮即可完成登录,成功登录后即跳转到后台。 至此,极验验证码的识别工作即全部完成,此识别方法同样适用于其他使用极验 3.0 的网站,原理都是相同的。
图 8-1 知网注册页面 表单的最后一项就是图形验证码,我们必须完全输入正确图中的字符才可以完成注册。
图 8-2 验证码 这样我们就可以得到一张验证码图片供下面测试识别使用了。
图 8-3 验证码 重新用下面的代码测试一下:
图 8-4 处理结果 经过处理之后我们发现原来的验证码中的线条已经被去除了,而且整个验证码变得黑白分明,这时重新识别验证码,代码如下:
总的来说,两款浏览器的内核是一样的,实现方式也是一样的,可以认为是开发版和正式版的区别,功能上基本是没有太大区别的。 Pyppeteer 就是依赖于 Chromium 这个浏览器来运行的。那么有了 Pyppeteer 之后,我们就可以免去那些繁琐的环境配置等问题。如果第一次运行的时候,Chromium 浏览器没有安全,那么程序会帮我们自动安装和配置,就免去了繁琐的环境配置等工作。另外 Pyppeteer 是基于 Python 的新特性 async 实现的,所以它的一些执行也支持异步操作,效率相对于 Selenium 来说也提高了。 那么下面就让我们来一起了解下 Pyppeteer 的相关用法吧。
可以看到它返回的就是 JavaScript 渲染后的页面。 pdf 方法也是类似的,只不过页面保存格式不一样,最后得到一个多页的 pdf 文件,样例如下:
可见其内容也是 JavaScript 渲染后的内容,另外这个方法还可以指定放缩大小 scale、页码范围 pageRanges、宽高 width 和 height、方向 landscape 等等参数,导出定制化的 pdf 用这个方法就十分方便。 最后我们又调用了 evaluate 方法执行了一些 JavaScript,JavaScript 传入的是一个函数,使用 return 方法返回了网页的宽高、像素大小比率三个值,最后得到的是一个 JSON 格式的对象,内容如下:
但是可以看到这就是一个光秃秃的浏览器而已,看一下相关信息:
看到了,这就是 Chromium,上面还写了开发者内部版本,可以认为是开发版的 Chrome 浏览器就好。 另外我们还可以开启调试模式,比如在写爬虫的时候会经常需要分析网页结构还有网络请求,所以开启调试工具还是很有必要的,我们可以将 devtools 参数设置为 True,这样每开启一个界面就会弹出一个调试窗口,非常方便,示例如下:
这时候我们可以看到上面的一条提示:”Chrome 正受到自动测试软件的控制”,这个提示条有点烦,那咋关闭呢?这时候就需要用到 args 参数了,禁用操作如下:
爬虫的时候看到这界面是很让人崩溃的吧,而且这时候我们还发现了页面的 bug,整个浏览器窗口比显示的内容窗口要大,这个是某些页面会出现的情况,让人看起来很不爽。 我们可以先解决一下这个显示的 bug,需要设置下 window-size 还有 viewport,代码如下:
OK,那刚才所说的 webdriver 检测问题怎样来解决呢?其实淘宝主要通过 window.navigator.webdriver 来对 webdriver 进行检测,所以我们只需要使用 JavaScript 将它设置为 false 即可,代码如下:
OK,这样的话我们就成功规避了 webdriver 的检测,使用鼠标拖动模拟就可以完成淘宝的登录了。 还有另一种方法可以进一步免去淘宝登录的烦恼,那就是设置用户目录。平时我们已经注意到,当我们登录淘宝之后,如果下次再次打开浏览器发现还是登录的状态。这是因为淘宝的一些关键 Cookies 已经保存到本地了,下次登录的时候可以直接读取并保持登录状态。 那么这些信息保存在哪里了呢?其实就是保存在用户目录下了,里面不仅包含了浏览器的基本配置信息,还有一些 Cache、Cookies 等各种信息都在里面,如果我们能在浏览器启动的时候读取这些信息,那么启动的时候就可以恢复一些历史记录甚至一些登录状态信息了。 这也就解决了一个问题:很多朋友在每次启动 Selenium 或 Pyppeteer 的时候总是是一个全新的浏览器,那就是没有设置用户目录,如果设置了它,每次打开就不再是一个全新的浏览器了,它可以恢复之前的历史记录,也可以恢复很多网站的登录信息。 那么这个怎么来做呢?很简单,在启动的时候设置 userDataDir 就好了,示例如下:
具体的介绍可以看官方的一些说明,如:



根据我学爬虫并不久的经验,通常只要把年月日之类的参数附加到 url 里面去,然后用
那个大表格的数据就是目标数据了,好像没什么了不起的—— 有点不对劲 目标数据所在网页的网址是这样的:
实话说,这是我第一次遇到要提交表单的活儿。以前可能是上天眷顾我,统统
不管三七二十一,
和
这三处。 第一处那里的下一行的
Yeah,数据都在!说明我的猜想是对的!那一会再试试我从没用过的
Yeah!拿到了,确实比自己手写提取方便,而且数值字符串自动转成数值,优秀!
州名、县名根据之前发现的两个 js 函数,要用
然后把程序开着过了一个周末,命令行里终于打出了
卤煮在此也推荐几个在线编辑的网站。诸君可自行前往练习使用。 
现代人都普遍比较焦虑,越来越多的人感到生活压力很大,在一二线城市不少白领人士更是已是患上“知识焦虑症”:这年头知识信息迭代太快,学习跟不上,别人懂的自己都不懂,总感觉自己欠缺的很多,没有技术和专长不知未来靠什么生存,担心自己长期落后他人从而被社会淘汰,从而产生了一种对未来不确定的心理恐惧。 于是,他们就急于渴求,希望能在短时间内学习大量知识希望从根本上解决自己的实际问题,拼命利用碎片化时间学习补充欠缺知识,不断完善自己的知识体系。这时知识付费的出现,正好满足了他们这些刚性需求。 再加上2018年前以逻辑思维为主一批内容供应商到处鼓吹和贩卖知识焦虑,在这种风气影响下连身边的很多小伙伴都购买了大量知识付费产品,但一年下来却发现这些知识根本没有学会几个,内容良莠不齐,服务跟不上,就算能坚持学完下来还是什么都不会,焦虑依然存在 。甚至更多人觉得其实知识付费就是一场骗局,从本质上来说知识付费并没有解决任何的问题,表面上只是缓解了一些焦虑,在短时间内让一些人自我感觉良好,实则上只是自欺欺人而已。 于是,一些感觉被欺骗的用户纷纷发声,对某些知识付费大号和机构更是愤怒抨击,在这些负面影响下这两年知识付费其实已逐渐降温并遭遇爆冷,甚至还有一些负面声音在说: 在线知识付费的寒冬是不是要来临了? 其实不然,纵观当下市场发展态势知识付费的前景仍然是广阔的,竞争激烈程度仍方兴未艾,当人们对知识的盲目消费退烧后,知识付费更多的是回归服务价值, 核心需求有两方面 : 一方面是为了提升欠缺的知识让自己具有更多的市场竞争力,另一方面也希望自己花钱买的知识付费产品是一些真正有帮助的东西,可帮自己迎来一个不错的未来。所以,知识付费的下一阶段必然聚焦于如何让学习用户获得真正有效的学习效果。 那么,知识付费下半场风口到底会吹去哪? 好学豚认为这一领域的大方向以后的发展趋势大致有如下特征:
▲ 图片来自:「伯爵旅拍」广告截图 广告的形式不断在变化,从广播、平面、视频,到 H5、直播,部分广告会以新颖的形式和优质的内容取胜,但人们看广告一直都是被动接受的过程。 上周蜘蛛侠上映,索尼在 Snapchat 上
▲图片来自:mobilemarketingmagazine 它让人们愿意看蜘蛛侠的广告,同时也让广告成了一种主动参与的过程。 接下来要讲的,就是未来这一种我们会主动点开的——VR 广告。
宜家是首批尝试购买 AR 技术并以此宣传的公司之一。 在
随后苹果发布了 ARkit 技术,Google、Facebook、亚马逊等大公司也在 2017 年和 2018 年期间发布了自己 AR 软件开发套件,以支持日后 AR 技术的发展。 Facebook 去年就为广告商提供了
除了家居服饰,美容时尚等行业也开始尝试利用 AR 营销,主要是为了弥补线上和线下的差距。 两周前,人们已经能在 YouTube 上一边看美妆博主的化妆教程,一边在分屏之下跟着博主一起涂口红试色,这个名为
甚至当你逛淘宝店,在前几周
这种自然而直观的方式,不仅让人们和品牌建立起更真实的关系,与以往广告最大的不同就是,人们还能随时参与、持续互动,并响应内容。
▲ 图片来自:unsplash 另外,AR 广告已经不再是单独的一个内容,而是进入我们的真实生活,或者进入其它我们沉浸的内容之中——广告本身就是商品的展示位,不会再有其它如美化特效、夸张视觉等因素插入和干扰。 而且这些 AR 广告最初打开的阀门,就掌握在消费者手上。 因为 AR 广告现在都需要申请对其相机/设备的访问,在非相机优先的应用中,也需要申请特定权限,因此你完全可以选择你需要的内容,并与之开始进一步互动。
▲ 图片来自:
▲ Google 推出名为 Swirl 的沉浸式显示,消费者可以 360 度查看、旋转、放大、缩小商品 在这个背景之下,市场研究公司
▲ 图片来自:unsplash 因为在高速运行的网络下,开发者不仅能够创造更高质量的 3D 可视化技术,消费者也能获得更多形式的沉浸式体验,品牌也能将其购物平台更多扩展到商店和传统网站之外的移动设备上,而且广告也不会再只限于移动设备的小屏幕。 还可以预见的是,5G 网络之下数据信息密度也会迅速加大,除了文本,还有图像、视频,人们接受的购物信息无疑更广、更深、更繁杂,而 AR 能够降低广告的感知成本,让人们消费数字内容将更简便和直观。
▲ 图片来自:unsplash 但现在 AR 广告还未普及的主要问题,就在于它的成本和技术。 比起其他广告形式来说,其实它的投入成本并不低。Digiday 指出
▲ 图片来自:unsplash AR 热潮刚刚开始真正起飞,我们现在看到的只是关于 AR 能带来什么以及它能做些什么的一瞥。不过苹果 2017 年推出 ARKit 时,首席执行官蒂姆・库克在
▲ 图片来自:
△ 官网:

△ 附上链接: 
















