目录
爬虫和反爬虫的斗争
爬虫建议
ajax基本介绍
动态了解HTML技术
获取ajax数据的方式
一.Selenium+chromedriver
Selenium介绍
Phantomjs快速入门
Phantomjs案例
selenium快速入门
定位元素
操作表单数据
鼠标行为链
Selenium页面等待
Cookie操作
页面等待
打开多窗口和切换页面
特征识别和设置无头窗口
selenium常用的js操作
二.图形验证码识别
Tesseract安装以及操作
云打码平台的使用
(1)尽量减少请求次数,保存或取的HTML,供查错和重复使用;
(2)关注网站的所有类型的页面,H5页面,APP等等;
(3)设置多伪装,代理IP,随即请求头等;
(4)利用多线程分布式,再不被发现的情况下我们尽可能提高速度。
(1)JS:是网络上最常用的脚本语言,它可以收集用户的跟踪数据,不需要重载页面直接提交表单,在页面嵌入多媒体文件,甚至运行网页;
(2)jQuery:jQuery是一个快速,简介的JavaScript框架,封装了JavaScript常用的功能代码;
(3)ajax:ajax可以使用网页实现异步更新,可以在不重新加载整个页面的情况下,对页面的某部分进行更新。
(1)直接分析ajax调用的接口。然后通过代码请求这个接口;
(2)使用Selenium+chromedriver模拟浏览器行为获取数据;
1.selenium是一个web的自动化测试工具,最初是为网站自动化测试而开发的,selenium可以直接运行在浏览器上,它支持所有主流的浏览器,可以接受指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏。
2.chromedriver是一个驱动Chorme浏览器的驱动程序,使用它才可以驱动浏览器。当然针对不同的浏览器有不同的driver。以下列出了不同浏览器及其对应的driver:
(1)Chrome:https://sites.google.com/a/chromium.org/chromedriver/downloads
(2)Firefox:Releases · mozilla/geckodriver · GitHub
(3)Edge:Microsoft Edge Driver - Microsoft Edge Developer
(4)Safari:WebDriver Support in Safari 10 | WebKit
Selenium
:pip install selenium无头浏览器:一个完整的浏览器内核,包含js解析引擎,渲染引擎,请求处理等,但是不包含显示和用户的页面的浏览器。
# 1.加载网页
from selenium import webdriver
driver = webdriver.PhantomJS("安装目录")
driver.get("https://www.baidu.com")
driver.save_screenshot("baidu.png")
# 2.定位和操作
driver.find_element_by_id("kw").send_keys("长城")
driver.find_element_by_id("su").click()
# 3.查看请求信息
driver.page_source
driver.get_cookies()
driver.current_url
# 4.退出
driver.quit()
注意:在新版的selenium中没有Phantomjs,所以这里不做更多的解释。
from selenium import webdriver
# 实例化浏览器
driver = webdriver.Chrome()
# 发送请求
driver.get('https://www.baidu.com')
# 退出浏览器
driver.quit()
(1)find_element_by_id:根据id查找某个元素:
submitTag = driver.find_element_by_id('su')
submitTag1 = driver.find_element(By.ID,'su')
(2)find_element_by_class_name:根据类名查找某个元素:
submitTag = driver.find_element_by_class_name('su')
submitTag1 = driver.find_element(By.CLASS_NAME,'su')
(3)find_element_by_name:根据name属性值查找某个元素:
submitTag = driver.find_element_by_name('email')
submitTag1 = driver.find_element(By.NAME,'email')
(4)find_element_by_tag_name:根据标签名查找某个元素:
submitTag = driver.find_element_by_tag_name('div')
submitTag1 = driver.find_element(By.TAG_NAME,'div')
(5)find_element_by_xpath:根据xpath语法查找某个元素:
submitTag = driver.find_element_by_xpath('//div')
submitTag1 = driver.find_element(By.XPATH,'//div')
注意使用上述的小by方法定位元素时,会有一个报警,这是因为这个方法即将过时,而大By方法,则不会出现报警,但是要导包:
from selenium.webdriver.common.by import By
且注意,find_element是获取第一个满足条件的元素。find_elements是获取所有满足条件的元素。
操作输入框:分为两步。
第一步:找到这个元素。
第二步:使用send_keys(values),将数据填充进去。
(1)使用clear方法可以清除输入框中的内容
inputTag.clear()
(2)操作按钮
操作按钮有很多种方式,比如单击,右击,双击等。这里讲两个最常用的。就是点击,直接调用click函数就可以了。
inputTag = driver.find_element_by_id('su')
# 点击函数
inputTag.click()
(3)选择select
select元素不能直接点击。因为点击后还需要选中元素。这时候selenium就专门为select标签提供了一个类from selenium.webdriver.support.ui import Select。将获取到的元素当成参数传到这个类中,创建这个对象。以后就可以使用这个对象进行选择了。(注意有时要切换到一个新的标签iframe中)
测试网站:https://www.17sucai.com/pins/demo-show?id=5926
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
import time
driver = webdriver.Chrome()
driver.get('https://www.17sucai.com/pins/demo-show?id=5926')
# 找到iframe
iframe_tag = driver.find_element_by_id('iframe')
# 切换到iframe
# 旧方法
# driver.switch_to_frame(iframe_tag)
# 新方法
driver.switch_to.frame(iframe_tag)
# 定位到select标签
# Message: no such element: Unable to locate element: {"method":"css selector","selector":".nojs"}
select_tag = driver.find_element_by_class_name('nojs')
new_select_tag = Select(select_tag)
# 根据值来选择
# new_select_tag.select_by_value('AU')
# 根据索引选择
new_select_tag.select_by_index(1)
"""
两种选择方式
一种是根据值来选择
另一种是通过索引选择
"""
有时候在页面中的操作可能要有很多步,那么这时候可以使用鼠标行为链类ActionChains来完成。比如现在要将鼠标移动到某个元素上并执行点击事件。
import time
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('https://www.baidu.com/?tn=49055317_3_hao_pg')
# 定位输入框
input_baidu = driver.find_element(By.XPATH, '//*[@id="kw"]')
# 定位百度按钮
btn_baidu = driver.find_element(By.XPATH, '//*[@id="su"]')
actions = ActionChains(driver)
# 往输入框种输入内容
actions.send_keys_to_element(input_baidu, 'python')
time.sleep(2)
# 移动鼠标位置
actions.move_to_element(btn_baidu)
actions.click()
# 提交行为链,必不可少
actions.perform()
还有更多的鼠标相关的操作
行为链小练习:
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
import time
# 1 找到滑块
# 2 拖动小滑块
# 3 到大滑块松开鼠标
driver = webdriver.Chrome()
driver.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
ifarme = driver.find_element(By.ID,'iframeResult')
driver.switch_to.frame(ifarme)
# 小滑块
div1 = driver.find_element(By.ID,'draggable')
# 大滑块
div2 = driver.find_element(By.ID,'droppable')
# 创建行为链
ac = ActionChains(driver)
# 点击并且不松开
ac.click_and_hold(div1)
# 拖动到大的div
# ac.move_to_element(div2)
# ac.move_by_offset(300,0)
for i in range(6):
time.sleep(0.1)
ac.move_by_offset(50, 0)
# 松开鼠标
ac.release()
# 提交行为链
ac.perform()
测试网站:https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable
(1)获取所有的cookie
cookies = driver.get_cookies()
(2)根据cookie的name获取cookie
value = driver.get_cookie(name)
(3)删除某个cookie
driver.delete_cookie('key')
案例:利用selenium得到的cookie登录qq空间:
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
import requests
# 通过selenium获取cookie
"""
1 通过selenium获取cookie值
2 进一步解析拼接cookie值
3 把最终拼接好的cookie值放测试代码中做测试
"""
# 1 通过selenium获取cookie值
# 加载驱动
driver = webdriver.Chrome()
# 打开一个网站
driver.get('https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=https%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=https%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_qr_app=手机QQ空间&pt_qr_link=http%3A//z.qzone.com/download.html&self_regurl=https%3A//qzs.qq.com/qzone/v6/reg/index.html&pt_qr_help_link=http%3A//z.qzone.com/download.html&pt_no_auth=0')
time.sleep(2)
# 找到头像
# link = driver.find_element_by_id('img_out_2857223830')
link = driver.find_element_by_class_name('face')
# 点击
link.click()
# 等待页面加载一会儿
time.sleep(2)
raw_cookie = driver.get_cookies()
# print(raw_cookie)
# 列表推导式
cookie = [item['name'] + '=' + item['value'] for item in raw_cookie]
# cookie_plus = "; ".join(cookie)
cookie_plus = "; ".join(i for i in cookie)
print(cookie_plus)
# cookie = []
# for i in raw_cookie:
# n = i['name']
# v = i['value']
# # n=v
# lst = n + '=' + v
# cookie.append(lst)
# # print(cookie)
# cookie_plus = "; ".join(cookie)
# print(cookie_plus)
# 测试代码 如果把通过selenium获取到的cookie放进请求头中 能够模拟登录成功 就证明我们通过selenium获取到的cookie是没有问题的
# url = 'https://user.qzone.qq.com/2857223830/infocenter'
#
# header = {
# 'cookie': cookie_plus,
# 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
# }
#
# html = requests.get(url, headers=header)
# with open('qzone.html', 'w', encoding='utf-8') as f:
# f.write(html.content.decode('utf-8'))
现在的网页越来越多采用了 Ajax 技术,这样程序便不能确定何时某个元素完全加载出来了。如果实际页面等待时间过长导致某个dom元素还没出来,但是你的代码直接使用了这个WebElement,那么就会抛出NullPointer的异常。为了解决这个问题。所以 Selenium 提供了两种等待方式:一种是隐式等待、一种是显式等待。
(1)隐式等待:调用driver.implicitly_wait。那么在获取不可用的元素之前,会先等待10秒中的时间。
driver.implicitly_wait(10)
(2)显式等待:显示等待是表明某个条件成立后才执行获取元素的操作。也可以在等待的时候指定一个最大的时间,如果超过这个时间那么就抛出一个异常。显示等待应该使用selenium.webdriver.support.excepted_conditions期望的条件和selenium.webdriver.support.ui.WebDriverWait来配合完成。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("https://www.baidu.com/")
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
一些其他的等待条件
有时候窗口中有很多子tab页面。这时候肯定是需要进行切换的。selenium提供了一个叫做switch_to_window来进行切换,具体切换到哪个页面,可以从driver.window_handles中找到。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
driver = webdriver.Chrome()
driver.get('https://www.baidu.com/?tn=49055317_3_hao_pg')
driver.implicitly_wait(3)
# driver.get('https://www.douban.com/?tn=49055317_3_hao_pg')
# 用js打开多个窗口
driver.execute_script('window.open("https://www.douban.com/?tn=49055317_3_hao_pg")')
time.sleep(2)
# 打开一个新窗口,如果想对新窗口进行操作,就要先切换selenium的视角
driver.switch_to.window(driver.window_handles[1])
# 打印当前视角的url
print(driver.current_url)
driver.close() # 使用close关闭之后,最好切换一下窗口,有残留。最好不要使用
(1)设置无头窗口(运行时不会在打开浏览器)
from selenium import webdriver
# 创建一个设置对象
option = webdriver.ChromeOptions()
option.add_argument('--headless')
driver = webdriver.Chrome(options=option)
driver.get('https://www.baidu.com')
driver.save_screenshot('baidu.png')
(2)特征识别
有时候我们在使用selenium爬取某网站时,会被网站识别成一个自动化测试的程序,从而会导致我们得不到想要的数据,我们这时需要去除一下特征识别:
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
# 去除识别 去除提示框
# option = webdriver.ChromeOptions()
# option.add_experimental_option('excludeSwitches', ['enable-automation'])
# option.add_experimental_option("detach", True)
#
# driver = webdriver.Chrome(options=option)
#
# driver.get('https://www.baidu.com')
# selenium打开的浏览器navigator.webdriver属性为true
# 把navigator.webdriver属性改为false
# script = 'Object.defineProperty(navigator, "webdriver", {get: () => false,});'
# driver.execute_script(script)
option = webdriver.ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
option.add_experimental_option("detach", True)
driver = webdriver.Chrome(options=option)
driver.get('http://www.porters.vip/features/webdriver.html')
driver.execute_script('Object.defineProperty(navigator, "webdriver", {get: () => false,});')
driver.find_element(By.XPATH,'//button[@class="btn btn-primary btn-lg"]').click()
(94条消息) selenium中常用的js操作_weixin_46583017的博客-CSDN博客https://blog.csdn.net/weixin_46583017/article/details/113738948?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164515283116780269839445%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=164515283116780269839445&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-1-113738948.first_rank_v2_pc_rank_v29&utm_term=selenium%E7%9A%84js%E6%93%8D%E4%BD%9C&spm=1018.2226.3001.4187
阻碍我们爬虫的。有时候正是在登录或者请求一些数据时候的图形验证码。因此这里我们讲解一种能将图片翻译成文字的技术。将图片翻译成文字一般被称为光学文字识别(Optical Character Recognition),简写为OCR。实现OCR的库不是很多,特别是开源的。因为这块存在一定的技术壁垒(需要大量的数据、算法、机器学习、深度学习知识等),并且如果做好了具有很高的商业价值。因此开源的比较少。这里介绍一个比较优秀的图像识别开源库:Tesseract。
在python中安装:pip install pytesseract
设置环境变量:
安装完成后,如果想要在命令行中使用Tesseract,那么应该设置环境变量。Mac和Linux在安装的时候就默认已经设置好了。在Windows下把tesseract.exe所在的路径添加到PATH环境变量中。
识别中文图像,需要下载语言安装包:
URL地址:https://github.com/tesseract-ocr/tessdat
# 命令行使用
# tesseract --help 查看帮助
# tesseract --list-langs 查看可识别的语言
# tesseract 图片名称 返回的文件名 识别前需要先cd到图片的目录
# tesseract 图片名称 返回的文件名 -l 需要识别的语言
在python中使用:
# 在python中使用tesseract识别图片 需要下载两个库
# 1 pip install pytesseract 用来操作 tesseract
# 2 pip install pillow 用于处理图片
# 导包
# 1 import pytesseract
# 2 from PIL import Image
import pytesseract
from PIL import Image
import urllib.request
# 打开图片
aaa = Image.open('aaa.png')
# 把图片识别成文字
result_aaa = pytesseract.image_to_string(aaa)
print(result_aaa)
bbb = Image.open('bbb.png')
# image_to_string(bbb,lang='chi_sim') 设置识别的语言 chi_sim(简体中文)
result_bbb = pytesseract.image_to_string(bbb,lang='chi_sim')
print(result_bbb)
# 验证码网址
url = 'https://passport.lagou.com/vcode/create?from=register&refresh=1513081451891'
# 保存图片 urllib.request.urlretrieve(网址,'图片名称')
# urllib.request.urlretrieve(url,'ccc.png')
ccc = Image.open('ccc.png')
result_ccc = pytesseract.image_to_string(ccc)
print(result_ccc)
由于tesseract对于一些高级的验证并无法做到准确,所以我们可以使用在线打码平台,这里推荐一个打码平台:超级鹰。网址:超级鹰验证码识别-专业的验证码云端识别服务,让验证码识别更快速、更准确、更强大 (chaojiying.com)https://www.chaojiying.com/
在超级鹰里面可以选择下载python的使用文档说明:
#!/usr/bin/env python
# coding:utf-8
import requests
from hashlib import md5
class Chaojiying_Client(object):
def __init__(self, username, password, soft_id):
self.username = username
password = password.encode('utf8')
self.password = md5(password).hexdigest()
self.soft_id = soft_id
self.base_params = {
'user': self.username,
'pass2': self.password,
'softid': self.soft_id,
}
self.headers = {
'Connection': 'Keep-Alive',
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
}
def PostPic(self, im, codetype):
"""
im: 图片字节
codetype: 题目类型 参考 http://www.chaojiying.com/price.html
"""
params = {
'codetype': codetype,
}
params.update(self.base_params)
files = {'userfile': ('ccc.jpg', im)}
r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
return r.json()
def ReportError(self, im_id):
"""
im_id:报错题目的图片ID
"""
params = {
'id': im_id,
}
params.update(self.base_params)
r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
return r.json()
if __name__ == '__main__':
chaojiying = Chaojiying_Client('用户名', '密码', '手动生成的软件id') #用户中心>>软件ID 生成一个替换 96001
# 打开图片
im = open('ccc.png', 'rb').read()
# print(chaojiying.PostPic(图片, 识别验证码的类型))
print(chaojiying.PostPic(im, 1902)) #1902 验证码类型 官方网站>>价格体系 3.4+版 print 后要加()
这里我们在使用的时候,直接调用即可使用方式如下:
注意我们不需要额外在下载其他的库,直接导入chaojiying这个包即可,有的时候导入包的时候会报错,不必理会,没有影响,只要我们将用户名,密码,id输入正确即可。
# 不影响使用
from chaojiying import Chaojiying_Client
# Chaojiying_Client('用户名', '用户密码', '手动生成的软件id') 创建对象
chaojiying = Chaojiying_Client('用户名', '密码', '手动生成的软件id')
# 打开图片
im = open('ddd.png', 'rb').read()
# print(chaojiying.PostPic(图片, 识别验证码的类型))
# chaojiying.PostPic(图片, 类型)
print(chaojiying.PostPic(im, 9004))