在参与一个项目的时候,得到了这样一个需求,需要我用爬虫爬取某个关键词的百度指数,而当我打开网址后http://index.baidu.com/,简单登陆输入关键词后,发现事情并不那么简单。
表面上看,这里只需要模拟鼠标操作,然后读取弹出的每一个ViewBox的数据便大功告成了。但百度不会让你那么简单获取数据。
通过这张图我们很开心地发现,百度指数具体的数字竟然是图片!!!每一个数字竟然都是一个图片!!!!显然,常规的思路已经无法驾驭百度指数了,在经过综合考虑过后,我决定采用Python的图像识别包来识别并爬取百度指数。
Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。它可以最大限度地模拟浏览器操作,每运行一个Selenium程序就会打开一个浏览器。
在本次数据采集工作中我们最为核心的是采用了ActionChains这个类,实现了模拟鼠标的移动。每次移动的距离就是从一天到下一天的距离。
ActionChains(browser).move_to_element_with_offset(xoyelement, x_0, y_0).perform()
而在获取到图像数据后,我们使用Python一个常用的图像识别包完成了图像数据向数字数据的转换。
image = Image.open(path + "/zoom/" + printString)
code = pytesseract.image_to_string(image)
Pytesseract的安装
sudo apt-get install tesseract-ocr
sudo apt-get install python-imaging
sudo pip install pytesseract
此处仅摘取部分重要代码
在登陆方面我没有下太大功夫,甚至没有实现自动化,因为百度指数在爬取的过程中不会出现需要重新登陆的情况,故用一个input()函数让程序暂停会儿,登陆后输入1便可。
#百度指数网站
url = "http://index.baidu.com/"
browser = webdriver.Chrome()
browser.get(url)
# 点击网页的登录按钮 browser.find_element_by_xpath("//ul[@class='usernav']/li[4]").click()
# 完成登陆后在控制台输入1
jud=input("登录好后输入1")
while 1:
if jud==1:
break
# 清空网页输入框
browser.find_element_by_id("schword").clear()
# 写入需要搜索的百度指数 browser.find_element_by_id("schword").send_keys(name)
# 点击搜索
browser.find_element_by_id("searchWords").click()
#找到ViewBox
imgelement = browser.find_element_by_xpath('//div[@id="viewbox"]')
#定位ViewBox
locations = imgelement.location
#确定截图范围
rangle = (int(int(locations['x'])), int(int(locations['y'])),
int(int(locations['x'])+100) ,
int(int(locations['y'])) + 80)
#保存整体网页截图
browser.save_screenshot(str(path) + "/raw/" + printString + ".png")
#打开网页截图
img = Image.open(str(path) + "/raw/" + printString + ".png")
#截取ViewBox
jpg = img.crop(rangle)
#打开截取的图片
jpgzoom = Image.open(str(imgpath))
(x, y) = jpgzoom.size
#设置放大倍数
x_s = 60 * 10
y_s = 20 * 10
#放大图片并保存
out = jpgzoom.resize((x_s, y_s), Image.ANTIALIAS)
out.save(path + "/zoom/" + printString, 'jpeg', quality=95)
#读取待识别的图片
image = Image.open(path + "/zoom/" + printString)
code = pytesseract.image_to_string(image)
由于不可抗的因素,有些时候鼠标移动时候不一定会弹出ViewBox,这会导致空指针错误,故在截图的时候需要先做ViewBox是否Exist的判断。为了优化该问题,我们也可以写一个循环,当ViewBox不出现的时候不断循环重复鼠标的操作。
cot=0
while (ExistBox(browser)==False):
cot+=1
ActionChains(browser).move_to_element_with_offset(xoyelement, x_0, y_0).perform()
if ExistBox(browser)==True:
break
if cot==6:
return None
图像识别包始终会存在错误,故有可能有一些普遍的识别错误,故可以对识别得到的数字做一个简单的替换处理
dealcode = code.replace("S", '5').replace(" ", "").replace(",", "").replace("E", "8").replace(".", ""). \
replace("'", "").replace(u"‘", "").replace("B", "8").replace("\"", "").replace("I", "1").replace(
"i", "").replace("-", ""). \
replace("$", "8").replace(u"’", "").strip()
本博客主要介绍的是百度指数爬虫主要涉及的几个模块,通过设计拼凑循环可以完成更多的任务。
代码已在Github上
https://github.com/TerenceLiu2/BaiduIndexCrawl