更优雅地在 Python 中写日志
原来我们在 Python 中写日志,使用的是 Python 自带的 logging 模块,要实现既在终端输出,又能写文件,并且日志文件还能 rotate ,代码需要十多行:
1 | import logging |
那有没有什么简单好用,for human
的写日志方案呢?
原来我们在 Python 中写日志,使用的是 Python 自带的 logging 模块,要实现既在终端输出,又能写文件,并且日志文件还能 rotate ,代码需要十多行:
1 | import logging |
那有没有什么简单好用,for human
的写日志方案呢?
有这样一个业务场景:
我有100篇故事,放在 MongoDB 里面。我做了一个 web 接口,每次请求返回一篇故事。希望能够实现:
每次请求返回的故事都不一样,在100次请求里面,每篇故事都需要返回。直到100篇故事全部返回完成。第101次与第1次相同,第102次与第2次相同……
在我们日常使用 Python 时,大家可能有这样一种认识:
True
,a is b 不一定为 True
True
,则 a == b 一定为 True
1 | >>> a = 'abc!' |
这是因为 ==
只比较值,而 is
同时比较值和内存地址。简单来说:你左手边有一个人,右手边有一个人,两个人长得一模一样,那么左手边的人==右手边的人
;你左手边有一个人,一分钟以后这个人走到了你的右手边,那么刚才左手边的人 is 现在右手边的人
但凡事总有意外,情况下面的代码:
为什么会出现这种情况?a is b
为 True,a == b
却为 False
。
你可以先停在这里,猜一下a 和 b 里面的值到底是什么东西。
现在来揭开答案,我们来网上看两行:
a 和 b 的值为♂
,它的意思是Not a Number
,非数。
♂
与任何数,包括它自己比较,结果都是 False,这是IEEE-754规定的:
Python 在实现这个数据的时候,根据 IEEE-754的要求,也做了限制:
相关的文档地址详见 Python 的 math 库
所以,这里 a == b 为 False,是一种特殊情况。并不是 Python 出现了错误。
当我们使用 Elasticsearch-py 批量插入数据到 ES 的时候,我们常常使用它的 helpers
模块里面的bulk
函数。其使用方法如下:
1 | from elasticsearch import helpers, Elasticsearch |
但这种方式有一个问题,它默认相当于upsert
操作。如果_id
对应的文档已经在 ES 里面了,那么数据会被更新。如果_id
对应的文档不在 ES 中,那么就插入。
开发这个项目,源自于我在知网发现了一篇关于自动化抽取新闻类网站正文的算法论文——《基于文本及符号密度的网页正文提取方法》)
这篇论文中描述的算法看起来简洁清晰,并且符合逻辑。但由于论文中只讲了算法原理,并没有具体的语言实现,所以我使用 Python 根据论文实现了这个抽取器。并分别使用今日头条、网易新闻、游民星空、观察者网、凤凰网、腾讯新闻、ReadHub、新浪新闻做了测试,发现提取效果非常出色,几乎能够达到100%的准确率。
在我以前的一篇文章:一日一技:如何正确移除Selenium中window.navigator.webdriver的值,我讲到了如何在Selenium启动的Chrome中,通过设置启动参数隐藏window.navigator.webdriver
,驳斥了网上垃圾文章中流传的使用JavaScript注入的弊端。
由于Selenium启动的Chrome中,有几十个特征可以被识别,所以在爬虫界已经没有以前那么受欢迎了。模拟浏览器的新秀Puppeteer异军突起,逐渐受到了爬虫界的关注。Puppeteer需要使用JavaScript来控制,如果你是用Python,那么就需要使用Pyppeteer.
如果你使用模拟浏览器爬淘宝,你会发现,无论怎么修改参数,Selenium总是可以立刻被识别。但是如果你使用了本文的方法,用Pyppeteer抓取淘宝,你就会发现另外一个广阔的天地。
今天,我们来讲讲如何在Pyppeteer中隐藏window.navigator.webdriver
知乎用户@Manjusaka 在阅读了我的文章《Python正则表达式,请不要再用re.compile了!!!》以后,写了一篇驳文《驳 <Python正则表达式,请不要再用re.compile了!!!>》
今天,我在这里回应一下这篇驳文。首先标题里面,我用的是回
,意为回复,而不是继续驳斥@Manjusaka的文章。因为没有什么好驳斥的,他的观点没有什么问题。
首先说明,我自己在公司的代码里面,也会使用re.compile
。但是,我现在仍然坚持我的观点,让看这篇文章的人,不要用re.compile
。
当我们使用Python从MongoDB里面读取数据时,可能会这样写代码:
1 | import pymongo |
短短4行代码,读取MongoDB里面的每一行数据,然后传入parse_data
做处理。处理完成以后再读取下一行。逻辑清晰而简单,能有什么问题?只要parse_data(row)不报错,这一段代码就完美无缺。
但事实并非这样。
看过《Python爬虫开发 从入门到实战》的同学,应该对multiprocessing
这个模块比较熟悉,在书上我使用这个模块通过几行代码实现了一个简单的多线程爬虫:
1 | import requests |
运行效果如下图所示: