目录
爬虫和反爬虫的斗争
爬虫建议
ajax基本介绍
动态了解HTML技术
获取ajax数据的方式
一.Selenium+chromedriver
Selenium介绍
Phantomjs快速入门
Phantomjs案例
selenium快速入门
定位元素
操作表单数据
鼠标行为链
Selenium页面等待
Cookie操作
页面等待
打开多窗口和切换页面
特征识别和设置无头窗口
selenium常用的js操作
二.图形验证码识别
Tesseract安装以及操作
云打码平台的使用
爬虫和反爬虫的斗争
爬虫建议
(1)尽量减少请求次数,保存或取的HTML,供查错和重复使用;
(2)关注网站的所有类型的页面,H5页面,APP等等;
(3)设置多伪装,代理IP,随即请求头等;
(4)利用多线程分布式,再不被发现的情况下我们尽可能提高速度。
ajax基本介绍
动态了解HTML技术
(1)JS:是网络上最常用的脚本语言,它可以收集用户的跟踪数据,不需要重载页面直接提交表单,在页面嵌入多媒体文件,甚至运行网页;
(2)jQuery:jQuery是一个快速,简介的JavaScript框架,封装了JavaScript常用的功能代码;
(3)ajax:ajax可以使用网页实现异步更新,可以在不重新加载整个页面的情况下,对页面的某部分进行更新。
获取ajax数据的方式
(1)直接分析ajax调用的接口。然后通过代码请求这个接口;
(2)使用Selenium+chromedriver模拟浏览器行为获取数据;
一.Selenium+chromedriver
Selenium介绍
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
- 下载chromedriver
- 百度搜索:淘宝镜像(npmmirror 中国镜像站)
- 安装总结:Selenium 入门教程(Python) – 简书
- 安装Selenium:pip install selenium
- 新的chromedriver 第地址 http://chromedriver.storage.googleapis.com/index.html
Phantomjs快速入门
无头浏览器:一个完整的浏览器内核,包含js解析引擎,渲染引擎,请求处理等,但是不包含显示和用户的页面的浏览器。
Phantomjs案例
# 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,所以这里不做更多的解释。
selenium快速入门
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()
还有更多的鼠标相关的操作
- click_and_hold(element):点击但不松开鼠标。
- context_click(element):右键点击。
- double_click(element):双击。
- 更多方法请参考:7. WebDriver API — Selenium Python Bindings 2 documentation
行为链小练习:
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
Selenium页面等待
Cookie操作
(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")) )
一些其他的等待条件
- presence_of_element_located:某个元素已经加载完毕了。
- presence_of_all_elements_located:网页中所有满足条件的元素都加载完毕了。
- element_to_be_clickable:某个元素是可以点击了。
- 更多条件请参考:5. Waits — Selenium Python Bindings 2 documentationhttp://selenium-python.readthedocs.io/waits.html
打开多窗口和切换页面
有时候窗口中有很多子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()
selenium常用的js操作
(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
二.图形验证码识别
Tesseract安装以及操作
阻碍我们爬虫的。有时候正是在登录或者请求一些数据时候的图形验证码。因此这里我们讲解一种能将图片翻译成文字的技术。将图片翻译成文字一般被称为光学文字识别(Optical Character Recognition),简写为OCR。实现OCR的库不是很多,特别是开源的。因为这块存在一定的技术壁垒(需要大量的数据、算法、机器学习、深度学习知识等),并且如果做好了具有很高的商业价值。因此开源的比较少。这里介绍一个比较优秀的图像识别开源库:Tesseract。
- Tesseract是一个将图像翻译成文字的OCR(光学文字识别,Optical Character Recognition),目前由谷歌赞助。Tesseract是目前公认最优秀、最准确的开源OCR库。Tesseract具有很高的识别度,也具有很高的灵活性,他可以通过训练识别任何字体
- Windows系统安装 在以下链接下载可执行文件,https://github.com/tesseract-ocr/
在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))
神龙|纯净稳定代理IP免费测试>>>>>>>>天启|企业级代理IP免费测试>>>>>>>>IPIPGO|全球住宅代理IP免费测试