引言
经过若干天不断地踩坑,总算能够正常获取百度指数啦,Just for fun~
百度指数爬虫开发的难点不在于爬虫本身,当然主要是因为 Python + Selenium 组合已经足够完成完整的登录+关键词查询的基本功能了。指数获取的难点在于:指数的数据是以 image text 的形式呈现,因此无法直接获取这种看似文本格式的数据。
image.png
登录
登录功能很容易借助 Selenium 实现,整体流程如下:
- 直接控制浏览器打开百度指数](https://index.baidu.com)) 页面;
- 优先查看下当前的状态,如果此时处于登录状态(可以看见用户名),就停止登录后续流程并返回;
- 在该页面模拟点击右上角的登录按钮,等待片刻即可看见弹窗;
- 在输入框中模拟输入用户名、密码并点击记住登录信息候选框后,点击登录按钮完成登录过程。
image.png
Cookie 管理
为了方便后期直接使用 Cookie 登录,我们可以在完成前一步的登录流程后保存浏览器的 Cookies,并在下次启动查询之前优先加载本地的 Cookies。完整的 Cookie 处理代码如下:
def dump_cookies(driver, to_file=None):
to_file = to_file or DEFAULT_CACHE_COOKIE_FILE
json.dump(driver.get_cookies(), open(to_file, 'w'), ensure_ascii=False, indent=2)
def setup_cookies(driver, from_file=None):
try:
from_file = from_file or DEFAULT_CACHE_COOKIE_FILE
driver.get(LOGIN_URL)
hint('Setup cookies from file "{}"'.format(from_file))
for cookie in json.load(open(from_file, 'r')):
try:
driver.add_cookie(cookie)
except WebDriverException:
pass
except Exception:
pass
finally:
return driver
搜索关键词
关键词搜索依然在 百度指数) 首页中可以看到搜索框,因此可以控制在该区域输入关键词并回车后即可得到关键词指数页面:
image.png提取指数
就目前来说,我只需要默认搜索条件下对应的整体搜索指数和移动搜索指数,然后也可以得到PC 端搜搜指数 了。以下是提取整体指数的流程:
- 首先定位到整体指数元素:
xpath(//table[contains(@class, "mtable")]//tr/td[2]//span[@class="ftlwhf enc2imgVal"][1])
,如此,我们可以得到该元素对象; - 获取上一步得到的元素的位置和大小(location & size):
loc, size = element.location, element.size
; - 紧接着,我们将获取当前页面的截图(这个在 Selenium 下很好做,直接 调用
driver.get_screenshot_as_png
方法即可; - 这一步比较关键,我们将使用
PIL
工具完成截图,截图方法如下:
# Get the location and size of the element
loc, size = element.location, element.size
# Crop the element from the full screenshot
element_image = crop_sub_image(loc, size, full_screenshot)
- 至此,我们将会得到如下类似的图片(放大了图片,实际截取的图片并没有那么大):
指数图片识别
既然是数字图像识别,比较好用的开源工具自然是网上推荐的 Tesseract OCR
,使用该工具识别上面的图片也非常简单:tesseract overall_index.png output.txt
,然后在 output.txt
中即可看到识别的结果。
至此,似乎已经完成任务了。但是,等等,还有一个问题没有解决,Tesseract OCR 真的在默认情况下可以准确识别各种指数?答案当然是不可以的,所以为了增加指数识别的精确度,我们需要对 Tesseract 进行训练。
训练 Tesseract OCR
准备工作
在对 Tesseract OCR 进行训练之前,我们需要做如下准备工作(以 Mac 环境为例):
- 安装 JRE 1.8 环境,并下载
jTessBoxEditor
辅助训练工具,将在后面使用它; - 安装 Tesseract 及其需要的训练工具(使用代理增加下载安装的速度):
http_proxy=localhost:8118 https_proxy=localhost:8118 brew install --with-training-tools tesseract
。
准备样本
- 为了得到更好的纠正训练数据,提前准备了一些指数图片作为样本(做了二值化处理,并放大了一定的倍数便于查看):
- 生成 TIFF 文件,这个使用
jTessBoxEditor
很容易做到:- 打开该工具后选择菜单
Tools->Merge TIFF
; - 在弹出的对话框中选择格式为
PNG
,并全选所有图片:
- 打开该工具后选择菜单
- 将 TIFF 文件保存到相关目录下,假设名为
num.font.duindex.tif
- 生成 box 文件,使用命令生成 box 文件:
tesseract num.font.duindex.tif num.font.duindex batch.nochop makebox
,可以得到.box
后缀的文件。
编辑 BOX 文件
- 使用
JTessBoxEditor
的Box Editor
面板,打开上一步生成的 box 文件; - 查看每一页识别的结果,如果存在问题,就一一修正,并在修正后
Save
下来,直到所有的都修正完毕为止(如下图的 7 被错误识别成了?
,在左侧输入正确的识别结果即可):
训练
- 打开
JTessBoxEditor
的Trainer
面板,导入上一步修正后的 box 文件; - 点击操作面板的
Run
按钮开始训练,很快即可完成训练:
- 训练结束后我们可以随意挑选几张图片进行测试,使用
Validate
功能即可,此处不再演示。
使用训练数据
- 上一步可以到一个
tessdata
目录,里面含有一个digit.traineddata
(文件名可能是其它的)文件; - 把
traineddata
拷贝到/usr/local/share/tesseract/tessdata
目录下(其它系统可能在不同的目录下); - 接下来,使用命令即可利用刚才训练的结果参与指数数据识别了:
tesseract overall_index.png output.txt -l digit
,注意,这里的-l digit
为上一步digit.traineddata
的文件名,然后多多测试查看效果吧。事实证明,识别准确度将会得到极大的提升,非常值得一试。
改进指数文本识别代码
当我们使用了训练后的数据后,识别结果的正确率将会大幅度提升,在 Python 中很容易改进先前的识别代码:
def recognize_image_text(img):
if img is None:
return None
return pytesseract.image_to_string(img, config='-l digit')
重要的依赖包
参考
- Selenium Python doc
- Tesseract official docs
- Training Tesseract
- firehood: Tesseract-OCR 字符识别---样本训练](http://blog.csdn.net/firehood_/article/details/8433077))
- Pillow: crop image
- rickArkin: 在Python下利用PIL实现可设定阈值的二值图像转换
版权声明
- 本文由 Christopher L 发表,采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。请确保你已了解许可协议,并在 转载 时声明。
- 本文固定链接:http://blog.chriscabin.com/?p=1545。
网友评论