利用python+selenium_phantomjs批量获取百度指数 第三步 代码
利用python+selenium_phantomjs批量获取百度指数 第三步 代码
爬虫张小呆 发表于7个月前
利用python+selenium_phantomjs批量获取百度指数 第三步 代码
  • 发表于 7个月前
  • 阅读 271
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 新注册用户 域名抢购1元起>>>   

这篇就直接上代码了,代码中贴上注释。

在贴代码之前先说一下,上一个步骤留下来的两个小问题。

一、使用多线程技术threading。

很简单,为了加快采集速度。但是这里也有一个弊病,就是同一个账号快速采集百度指数,百度指数会出验证码的。为了防止验证码的出现,这里有两个思路来解决。

1.1、适量降低采集速度,即减少线程数。笔者测试当线程开到20个左右的时候,大概半个小时后会出现验证码。

1.2、可以使用多账号进行采集,在使用多账号采集时,需要注意每个账号的cookie保存成一个独立的文件,不然就乱了。笔者这里没有深究下去。

二、使用phantomjs

phantomjs, 你就可以理解成一个浏览器,只不过没有界面而已。这样它就能省下来挺多的资源。也可以在服务器中执行了。需要注意的是在执行phantomjs中,在载入cookie时,有些字段要独立进行判断。否则会报错。

# -*- coding:utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import Image
import time
import os
import random
from urllib import quote,unquote
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from threading import Thread
import pickle
import requests
# import Queue

class BaiduIndex(object):

	def __init__(self):
		self.numdict = self.get_numberdict() # 拿到百度数字与向量的键值对
		keys = list()
		vals = list()
		for k, v in self.numdict.items():
			keys.append(k)
			vals.append(v)
		self.keys = keys
		self.vals = vals

		tof = self.judgment() # 判断当前的cookies是否能用

		if tof == False: # 不能用的时候换cookies
			self.change_cookies()
		#~ dcap = dict(DesiredCapabilities.PHANTOMJS)
		#~ dcap["phantomjs.page.settings.userAgent"] = ("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")
		#~ self.driver=webdriver.PhantomJS(executable_path='/usr/bin/phantomjs', desired_capabilities= dcap)
		# self.driver=webdriver.Chrome()
		self.driver = webdriver.PhantomJS(executable_path='/usr/bin/phantomjs')
        # 以上注释是在调试过程中,用于方便肉眼调试使用的Chrome()浏览器
                
		self.driver.get("http://index.baidu.com")
        # 载入之前保存在文件中的cookies
		cookies = pickle.load(open("cookies/cookies.pkl", "rb"))
        # 因为phantomjs与其他浏览器不太一样,需要额外做一些微调
		for cookie in cookies:
			if cookie.has_key('expiry'):
				try:
					driver.add_cookie({k: cookie[k] for k in ('name', 'value', 'domain', 'path', 'expiry')})
				except:
					for i in cookie.keys():
						if cookie[i] == 'index.baidu.com':
							cookie[i] = '.index.baidu.com'
					self.driver.add_cookie({k: cookie[k] for k in ('name', 'value', 'domain', 'path', 'expiry')})
			else:
				self.driver.add_cookie({k: cookie[k] for k in ('name', 'value', 'domain', 'path')})

	def judgment(self): # 这个是判断当前cookie是否有效的函数。
		cookies = pickle.load(open("cookies/cookies.pkl", "rb")) # 载入cookies
		s = requests.Session()
		for cookie in cookies:
			s.cookies.set(cookie['name'], cookie['value'])
		response = s.get("http://index.baidu.com/?tpl=trend&word=%B9%C7%C3%DC%B6%C8%D2%C7")
		bodyStr = response.text
		response.close()
		ff = bodyStr.find('ctlName="word"') # 只要能找到这个元素就说明cookie是正确的
		if ff != -1:
			return True
		else:
			return False

	def change_cookies(self):# 这个函数是用来更改cookie滴
		#~ dcap = dict(DesiredCapabilities.PHANTOMJS)
		#~ dcap["phantomjs.page.settings.userAgent"] = ("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")
		#~ self.driver=webdriver.PhantomJS(executable_path='/usr/bin/phantomjs', desired_capabilities= dcap)
		# driver=webdriver.Chrome()
        # 以上注释是在调试过程中,用于方便肉眼调试使用的Chrome()浏览器
        
        """
			输入账号密码开始
        """
		driver = webdriver.PhantomJS(executable_path='/usr/bin/phantomjs')
		driver.get('http://index.baidu.com/?tpl=trend&word=%B9%C7%C3%DC%B6%C8%D2%C7')
		e1 = driver.find_element_by_id("TANGRAM_12__userName")
		e1.send_keys("这里填写你的账号")
		e2 = driver.find_element_by_id("TANGRAM_12__password")
		e2.send_keys("这里填写你的密码")
		e3 = driver.find_element_by_id("TANGRAM_12__submit")
		e3.click()
        """
			输入账号密码结束
        """
		cookies = driver.get_cookies()
		driver.quit()
		pickle.dump(cookies, open("cookies/cookies.pkl","wb"))

	# 拿到数字和文本组合的向量字典
	def get_numberdict(self):
		"""
		具体的向量文件保存在文件夹“text”中,怎样拿到向量文件,可以看我的另一篇博客
		《我是怎样利用python PIL将图片数字读出来的?》
		"""
		numdict = dict()
		path = "text"
		file_list = os.listdir(path)
		for filex in file_list:
			filex = path + '/' + filex
			f = open(filex)
			c = f.read()
			key = filex.split('/')[1].split('.')[0]
			numdict[key] = c
		return numdict

	# 拿到pc指数和移动指数
	def get_index(self, url):
		#~ js='window.open("%s");' % url
		#~ self.driver.execute_script(js)
		#~ handles = self.driver.window_handles
		#~ self.driver.switch_to.window(handles[len(handles) - 1])
		self.driver.get(url)
		self.driver.implicitly_wait(10)
		try:
			locator = (By.XPATH, '//div[@class="lrRadius"]/span[@class="ftlwhf enc2imgVal"]')
			WebDriverWait(self.driver, 20, 0.5).until(EC.presence_of_element_located(locator))
			# 这里是等待locator元素的出现在执行下一步的意思,为的是防止页面渲染不完整的情况
		except:
			return None, None
		time.sleep(3.5)
		# 强制等待一段时间,同样是为了等待页面中百度指数的图片渲染出来。不同的是要根据个人的网速决定睡眠时间,网速好睡的短一些
		e2 = self.driver.find_elements_by_css_selector("span[class='ftlwhf enc2imgVal']")
		lc1 = e2[0].location
		lc2 = e2[1].location
		
		# lc1, lc2是记录下百度指数图片的位置,方便下一步截图
		
		filename = unquote(url.split('&word=')[1])
		self.driver.get_screenshot_as_file("screenshot/%s.png" % filename.decode('gbk'))
		# 截屏操作
		im = Image.open("screenshot/%s.png" % filename.decode('gbk'))
		x1 = int(lc1['x'])
		y1 = int(lc1['y'])
		x2 = int(lc2['x'])
		y2 = int(lc2['y'])
		box1 = (x1, y1, x1 + 92, y1 + 19)
		region1 = im.crop(box1)
		box2 = (x2, y2, x2 + 92, y2 + 19)
		region2 = im.crop(box2)
		
		# 截两张图,一张是pc指数,一张是移动指数
		return region1, region2
		# 这里就已经拿到了百度指数的图片了,不信可以show()一下。

	# 将图片对象分割成图片对象列表
	def splitimage(self,filee):
		region_list = list()
		width = filee.width
		height = filee.height
		i = width - 8
		while i > 8:
			box = (i, 0, i+8, height)
			region = filee.crop(box)
			i -= 8
			region_list.append(region)
		return region_list

	# 拿到数字
	def get_number(self, im):
		# 将图片对象转换为字符串
		text = self.image2text(im)
		if text in self.vals:
			i = self.vals.index(text)
			return self.keys[i]
		else:
			return None

	# 将图片对象转换成字符串
	def image2text(self, im):
		width = im.size[0]
		height = im.size[1]

		tmstr = ""
		for i in range(0,width):
			for j in range(0,height):
				cl=im.getpixel((i,j))
				clall = cl[0] + cl[1] + cl[2]
				if(clall==231):
					#黑色
					tmstr = tmstr + "1"
				else:
					tmstr = tmstr + "0"
			tmstr = tmstr + "\n"
		return tmstr

	"""
	以上三个自定义函数,我在以前的博客里就说过了
	详见《我是怎样利用python PIL将图片数字读出来的?》
	"""
	def do_main(self):
		"""
		这是主函数,其实也没什么可说的了,主要操作在上面都已经说完了,
		无非就是把上面的操作拼接一下,方便用多线程调用。
		"""
		while not q.empty():
			try:
				tw = q.get()
				word = quote(tw)
				url = 'http://index.baidu.com/?tpl=trend&word=%s' % word

				pcindex, mobileindex = self.get_index(url)
				word = unquote(url.split('&word=')[-1])
				if pcindex != None and mobileindex != None:
					region_list1 = self.splitimage(pcindex)
					region_list2 = self.splitimage(mobileindex)
					nus1 = ""
					for r in region_list1:
						nu = self.get_number(r)
						if nu != None:
							nus1 = nus1 + nu

					nus2 = ""
					for r in region_list2:
						nu = self.get_number(r)
						if nu != None:
							nus2 = nus2 + nu
					txt = open(u'百度指数.txt', 'a')
					txt.write(word + ':' + str(nus1[::-1]) + ' ' + nus2[::-1] + '\n')
					txt.close()
					print tw.decode('gbk'), nus1[::-1], nus2[::-1]

				else:
					print tw.decode('gbk'), u"没有指数"
					txt = open(u'百度指数.txt', 'a')
					txt.write(word + ':' + 'No Index' + '\n')
					txt.close()
				log = open(u'log', 'a')
				log.write(word+',')
				log.close()
			except Exception as e:
				raise e
				continue


contents = open('words').read().split('\n')
if os.path.exists('log'):
	contentb = open('log').read().split(',')
else:
	contentb = list()
for con in contentb:
	if con in contents:
		contents.remove(con)
q = Queue.Queue()
for c in contents:
	q.put(c)


threads = list()
for i in xrange(5):
	a = BaiduIndex()
	t = Thread(target=a.do_main)
	threads.append(t)

# 启动所有线程
for thr in threads:
	thr.start()

 

这里只贴了一个主文件。全部代码请见我的公众号“爬虫张小呆”

有代码经验的同学请见我的github:

https://github.com/plus0318/BaiduIndex

标签: Python Selenium
共有 人打赏支持
粉丝 2
博文 17
码字总数 10731
×
爬虫张小呆
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: