锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

Python爬虫第二课 Selenium介绍和反爬技术

时间:2023-10-26 10:37:02 jk9301b01振动变送器

selenium的介绍

知识点:

1. selenium显示运行效果

Selenium是一个Web最初为网站自动化测试开发的自动化测试工具,Selenium 支持所有主流浏览器的浏览器(包括PhantomJS这些无界面浏览器)可以接收指令,让浏览器自动加载页面,获取所需的数据,甚至截图页面。我们可以用selenium以前写的爬虫很容易完成。接下来我们来看看。selenium的运行效果

1.1 chrome浏览器的运行效果

在下载好chromedriver以及安装好selenium模块完成后,执行以下代码并观察运行过程

from selenium import webdriver   # 如果driver如果不添加环境变量,则需要将其添加到环境变量中driver绝对路径赋值executable_path参数 # driver = webdriver.Chrome(executable_path='/home/worker/Desktop/driver/chromedriver')  # 如果driver添加了环境变量则不需要设置executable_path driver = webdriver.Chrome()  # 向一个url发起请求 driver.get("http://www.itcast.cn/")  # 将网页保存为图片,谷歌浏览器69版以上将无法使用截图功能 # driver.save_screenshot("itcast.png")  print(driver.title) # 打印页面的标题  # 退出模拟浏览器 driver.quit() # 一定要退出!不退出会有残留过程! 

1.2 phantomjs无界面浏览器的运行效果

PhantomJS 是一个基于Webkit无界面的无界面(headless)浏览器将网站加载到内存并执行页面 JavaScript。下载地址:http://phantomjs.org/download.html

from selenium import webdriver   # 指定driver的绝对路径 driver = webdriver.PhantomJS(executable_path='/home/worker/Desktop/driver/phantomjs')  # driver = webdriver.Chrome(executable_path='/home/worker/Desktop/driver/chromedriver')  # 向一个url发起请求 driver.get("http://www.itcast.cn/")  # 将网页保存为图片 driver.save_screenshot("itcast.png")  # 退出模拟浏览器 driver.quit() # 一定要退出!不退出会有残留过程! 

1.3 观察运行效果

  • python代码可以自动调用谷歌浏览或phantomjs无界面浏览器控制其自动访问网站

1.4 使用无头浏览器和有头浏览器的场景

  • 通常在开发过程中,我们需要检查运行过程中的各种情况,所以我们通常使用有头浏览器
  • 当项目完成部署时,平台通常使用服务器版本的操作系统,服务器版本的操作系统必须使用无头浏览器才能正常运行

2. selenium工作原理

本地使用浏览器API,封装成一套更面向对象的对象Selenium WebDriver API,直接操作浏览器页面中的元素,甚至操作浏览器本身(截图、窗口大小、启动、关闭、插件安装、配置证书等)

selenium的工作原理

  • webdriver本质是一个web-server,对外提供webapi,其中包装了浏览器的各种功能
  • 不同的浏览器使用不同的浏览器webdriver

知识点:理解 selenium的工作原理

3. selenium安装简单

我们使用谷歌浏览器chromedriver为例

3.1 在python安装在虚拟环境中selenium模块

pip/pip3 install selenium

3.2 下载版本符合的webdriver

以chrome谷歌浏览器为例

  1. 查看谷歌浏览器的版本

  2. 访问https://npm.taobao.org/mirrors/chromedriver,点击进入不同版本的chromedriver下载页面

  3. 点击notes.txt进入版本说明页面

  4. 查看chrome和chromedriver匹配的版本

  5. 根据操作系统下载正确版本的chromedriver

  6. 解压压缩包后获取python代码可以调用的谷歌浏览器的webdriver可执行文件

    • windows为chromedriver.exe

    • linux和macos为chromedriver

  7. chromedriver环境的配置

    • windows环境下需要将 chromedriver.exe 所在的目录设置为path环境变量中的路径
    • linux/mac环境下,将 chromedriver 所在的目录设置到系统的PATH环境值中

知识点:了解 selenium以及chromedriver的安装

4. selenium的简单使用

接下来我们就通过代码来模拟百度搜索

import time
from selenium import webdriver

# 通过指定chromedriver的路径来实例化driver对象,chromedriver放在当前目录。
# driver = webdriver.Chrome(executable_path='./chromedriver')
# chromedriver已经添加环境变量
driver = webdriver.Chrome()

# 控制浏览器访问url地址
driver.get("https://www.baidu.com/")

# 在百度搜索框中搜索'python'
driver.find_element_by_id('kw').send_keys('python')
# 点击'百度搜索'
driver.find_element_by_id('su').click()

time.sleep(6)
# 退出浏览器
driver.quit()
  • webdriver.Chrome(executable_path='./chromedriver')中executable参数指定的是下载好的chromedriver文件的路径
  • driver.find_element_by_id('kw').send_keys('python')定位id属性值是’kw’的标签,并向其中输入字符串’python’
  • driver.find_element_by_id('su').click()定位id属性值是su的标签,并点击
    • click函数作用是:触发标签的js的click事件

知识点:掌握 标签对象click点击以及send_keys输入

selenium提取数据

知识点:
  • 了解 driver对象的常用属性和方法
  • 掌握 driver对象定位标签元素获取标签对象的方法
  • 掌握 标签对象提取文本和属性值的方法

1. driver对象的常用属性和方法

在使用selenium过程中,实例化driver对象后,driver对象有一些常用的属性和方法

  1. driver.page_source 当前标签页浏览器渲染之后的网页源代码
  2. driver.current_url 当前标签页的url
  3. driver.close() 关闭当前标签页,如果只有一个标签页则关闭整个浏览器
  4. driver.quit() 关闭浏览器
  5. driver.forward() 页面前进
  6. driver.back() 页面后退
  7. driver.screen_shot(img_name) 页面截图

知识点:了解 driver对象的常用属性和方法

2. driver对象定位标签元素获取标签对象的方法

在selenium中可以通过多种方式来定位标签,返回标签元素对象

find_element_by_id 						(返回一个元素)
find_element(s)_by_class_name 			(根据类名获取元素列表)
find_element(s)_by_name 				(根据标签的name属性值返回包含标签对象元素的列表)
find_element(s)_by_xpath 				(返回一个包含元素的列表)
find_element(s)_by_link_text 			(根据连接文本获取元素列表)
find_element(s)_by_partial_link_text 	(根据链接包含的文本获取元素列表)
find_element(s)_by_tag_name 			(根据标签名获取元素列表)
find_element(s)_by_css_selector 		(根据css选择器来获取元素列表)
  • 注意:
    • find_element和find_elements的区别:
      • 多了个s就返回列表,没有s就返回匹配到的第一个标签对象
      • find_element匹配不到就抛出异常,find_elements匹配不到就返回空列表
    • by_link_text和by_partial_link_tex的区别:全部文本和包含某个文本
    • 以上函数的使用方法
      • driver.find_element_by_id('id_str')

知识点:掌握 driver对象定位标签元素获取标签对象的方法

3. 标签对象提取文本内容和属性值

find_element仅仅能够获取元素,不能够直接获取其中的数据,如果需要获取数据需要使用以下方法

  • 对元素执行点击操作element.click()

    • 对定位到的标签对象进行点击操作
  • 向输入框输入数据element.send_keys(data)

    • 对定位到的标签对象输入数据
  • 获取文本element.text

    • 通过定位获取的标签对象的text属性,获取文本内容
  • 获取属性值element.get_attribute("属性名")

    • 通过定位获取的标签对象的get_attribute函数,传入属性名,来获取属性的值

  • 代码实现,如下:

    from selenium import webdriver
    
    driver = webdriver.Chrome()
    
    driver.get('http://www.itcast.cn/')
    
    ret = driver.find_elements_by_tag_name('h2')
    print(ret[0].text) # 
    
    ret = driver.find_elements_by_link_text('黑马程序员')
    print(ret[0].get_attribute('href'))
    
    driver.quit()
    

知识点:掌握 元素对象的操作方法

selenium的其它使用方法

知识点:
  • 掌握 selenium控制标签页的切换
  • 掌握 selenium控制iframe的切换
  • 掌握 利用selenium获取cookie的方法
  • 掌握 手动实现页面等待
  • 掌握 selenium控制浏览器执行js代码的方法
  • 掌握 selenium开启无界面模式
  • 了解 selenium使用代理ip
  • 了解 selenium替换user-agent

1. selenium标签页的切换

当selenium控制浏览器打开多个标签页时,如何控制浏览器在不同的标签页中进行切换呢?需要我们做以下两步:

  • 获取所有标签页的窗口句柄

  • 利用窗口句柄字切换到句柄指向的标签页

    • 这里的窗口句柄是指:指向标签页对象的标识
    • 关于句柄请课后了解更多,本小节不做展开
  • 具体的方法

    # 1. 获取当前所有的标签页的句柄构成的列表
    current_windows = driver.window_handles
    
    # 2. 根据标签页句柄列表索引下标进行切换
    driver.switch_to.window(current_windows[0])
    
  • 参考代码示例:

    import time
    from selenium import webdriver
    
    driver = webdriver.Chrome()
    driver.get("https://www.baidu.com/")
    
    time.sleep(1)
    driver.find_element_by_id('kw').send_keys('python')
    time.sleep(1)
    driver.find_element_by_id('su').click()
    time.sleep(1)
    
    # 通过执行js来新开一个标签页
    js = 'window.open("https://www.sogou.com");'
    driver.execute_script(js)
    time.sleep(1)
    
    # 1. 获取当前所有的窗口
    windows = driver.window_handles
    
    time.sleep(2)
    # 2. 根据窗口索引进行切换
    driver.switch_to.window(windows[0])
    time.sleep(2)
    driver.switch_to.window(windows[1])
    
    time.sleep(6)
    driver.quit()
    

知识点:掌握 selenium控制标签页的切换

2. switch_to切换frame标签

iframe是html中常用的一种技术,即一个页面中嵌套了另一个网页,selenium默认是访问不了frame中的内容的,对应的解决思路是driver.switch_to.frame(frame_element)。接下来我们通过qq邮箱模拟登陆来学习这个知识点
  • 参考代码:

    import time
    from selenium import webdriver
    
    driver = webdriver.Chrome()
    
    url = 'https://mail.qq.com/cgi-bin/loginpage'
    driver.get(url)
    time.sleep(2)
    
    login_frame = driver.find_element_by_id('login_frame') # 根据id定位 frame元素
    driver.switch_to.frame(login_frame) # 转向到该frame中
    
    driver.find_element_by_xpath('//*[@id="u"]').send_keys('1596930226@qq.com')
    time.sleep(2)
    
    driver.find_element_by_xpath('//*[@id="p"]').send_keys('hahamimashicuode')
    time.sleep(2)
    
    driver.find_element_by_xpath('//*[@id="login_button"]').click()
    time.sleep(2)
    
    """操作frame外边的元素需要切换出去"""
    windows = driver.window_handles
    driver.switch_to.window(windows[0])
    
    content = driver.find_element_by_class_name('login_pictures_title').text
    print(content)
    
    driver.quit()
    
  • 总结:

    • 切换到定位的frame标签嵌套的页面中

      • driver.switch_to.frame(通过find_element_by函数定位的frame、iframe标签对象)
    • 利用切换标签页的方式切出frame标签

      • windows = driver.window_handles
        driver.switch_to.window(windows[0])
        

知识点:掌握 selenium控制frame标签的切换

3. selenium对cookie的处理

selenium能够帮助我们处理页面中的cookie,比如获取、删除,接下来我们就学习这部分知识

3.1 获取cookie

driver.get_cookies()返回列表,其中包含的是完整的cookie信息!不光有name、value,还有domain等cookie其他维度的信息。所以如果想要把获取的cookie信息和requests模块配合使用的话,需要转换为name、value作为键值对的cookie字典

# 获取当前标签页的全部cookie信息
print(driver.get_cookies())
# 把cookie转化为字典
cookies_dict = {cookie[‘name’]: cookie[‘value’] for cookie in driver.get_cookies()}

3.2 删除cookie

#删除一条cookie
driver.delete_cookie("CookieName")

# 删除所有的cookie
driver.delete_all_cookies()

知识点:掌握 利用selenium获取cookie的方法

4. selenium控制浏览器执行js代码

selenium可以让浏览器执行我们规定的js代码,运行下列代码查看运行效果

import time
from selenium import webdriver

driver = webdriver.Chrome()
driver.get("http://www.itcast.cn/")
time.sleep(1)

js = 'window.scrollTo(0,document.body.scrollHeight)' # js语句
driver.execute_script(js) # 执行js的方法

time.sleep(5)
driver.quit()
  • 执行js的方法:driver.execute_script(js)

知识点:掌握 selenium控制浏览器执行js代码的方法

5. 页面等待

页面在加载的过程中需要花费时间等待网站服务器的响应,在这个过程中标签元素有可能还没有加载出来,是不可见的,如何处理这种情况呢?

  1. 页面等待分类
  2. 强制等待介绍
  3. 显式等待介绍
  4. 隐式等待介绍
  5. 手动实现页面等待

5.1 页面等待的分类

首先我们就来了解以下selenium页面等待的分类

  1. 强制等待
  2. 隐式等待
  3. 显式等待

5.2 强制等待(了解)

  • 其实就是time.sleep()
  • 缺点时不智能,设置的时间太短,元素还没有加载出来;设置的时间太长,则会浪费时间

5.3 隐式等待

  • 隐式等待针对的是元素定位,隐式等待设置了一个时间,在一段时间内判断元素是否定位成功,如果完成了,就进行下一步

  • 在设置的时间内没有定位成功,则会报超时加载

  • 示例代码

    from selenium import webdriver
    
    driver = webdriver.Chrome()  
    
    driver.implicitly_wait(10) # 隐式等待,最长等20秒  
    
    driver.get('https://www.baidu.com')
    
    driver.find_element_by_xpath()
    
    

5.4 显式等待(了解)

  • 每经过多少秒就查看一次等待条件是否达成,如果达成就停止等待,继续执行后续代码

  • 如果没有达成就继续等待直到超过规定的时间后,报超时异常

  • 示例代码

    from selenium import webdriver  
    from selenium.webdriver.support.wait import WebDriverWait  
    from selenium.webdriver.support import expected_conditions as EC  
    from selenium.webdriver.common.by import By 
    
    driver = webdriver.Chrome()
    
    driver.get('https://www.baidu.com')
    
    # 显式等待
    WebDriverWait(driver, 20, 0.5).until(
        EC.presence_of_element_located((By.LINK_TEXT, '好123')))  
    # 参数20表示最长等待20秒
    # 参数0.5表示0.5秒检查一次规定的标签是否存在
    # EC.presence_of_element_located((By.LINK_TEXT, '好123')) 表示通过链接文本内容定位标签
    # 每0.5秒一次检查,通过链接文本内容定位标签是否存在,如果存在就向下继续执行;如果不存在,直到20秒上限就抛出异常
    
    print(driver.find_element_by_link_text('好123').get_attribute('href'))
    driver.quit() 
    

5.5 手动实现页面等待

在了解了隐式等待和显式等待以及强制等待后,我们发现并没有一种通用的方法来解决页面等待的问题,比如“页面需要滑动才能触发ajax异步加载”的场景,那么接下来我们就以淘宝网首页为例,手动实现页面等待

  • 原理:
    • 利用强制等待和显式等待的思路来手动实现
    • 不停的判断或有次数限制的判断某一个标签对象是否加载完毕(是否存在)
  • 实现代码如下:
import time
from selenium import webdriver
driver = webdriver.Chrome('/home/worker/Desktop/driver/chromedriver')

driver.get('https://www.taobao.com/')
time.sleep(1)

# i = 0
# while True:
for i in range(10):
    i += 1
    try:
        time.sleep(3)
        element = driver.find_element_by_xpath('//div[@class="shop-inner"]/h3[1]/a')
        print(element.get_attribute('href'))
        break
    except:
        js = 'window.scrollTo(0, {})'.format(i*500) # js语句
        driver.execute_script(js) # 执行js的方法
driver.quit()

知识点:掌握 手动实现页面等待

6. selenium开启无界面模式

绝大多数服务器是没有界面的,selenium控制谷歌浏览器也是存在无界面模式的,这一小节我们就来学习如何开启无界面模式(又称之为无头模式)

  • 开启无界面模式的方法
    • 实例化配置对象
      • options = webdriver.ChromeOptions()
    • 配置对象添加开启无界面模式的命令
      • options.add_argument("--headless")
    • 配置对象添加禁用gpu的命令
      • options.add_argument("--disable-gpu")
    • 实例化带有配置对象的driver对象
      • driver = webdriver.Chrome(chrome_options=options)
  • 注意:macos中chrome浏览器59+版本,Linux中57+版本才能使用无界面模式!
  • 参考代码如下:
from selenium import webdriver

options = webdriver.ChromeOptions() # 创建一个配置对象
options.add_argument("--headless") # 开启无界面模式
options.add_argument("--disable-gpu") # 禁用gpu

# options.set_headles() # 无界面模式的另外一种开启方式
driver = webdriver.Chrome(chrome_options=options) # 实例化带有配置的driver对象

driver.get('http://www.itcast.cn')
print(driver.title)
driver.quit()

知识点:掌握 selenium开启无界面模式

7. selenium使用代理ip

selenium控制浏览器也是可以使用代理ip的!

  • 使用代理ip的方法

    • 实例化配置对象
      • options = webdriver.ChromeOptions()
    • 配置对象添加使用代理ip的命令
      • options.add_argument('--proxy-server=http://202.20.16.82:9527')
    • 实例化带有配置对象的driver对象
      • driver = webdriver.Chrome('./chromedriver', chrome_options=options)
  • 参考代码如下:

    from selenium import webdriver
    
    options = webdriver.ChromeOptions() # 创建一个配置对象
    options.add_argument('--proxy-server=http://202.20.16.82:9527') # 使用代理ip
    
    driver = webdriver.Chrome(chrome_options=options) # 实例化带有配置的driver对象
    
    driver.get('http://www.itcast.cn')
    print(driver.title)
    driver.quit()
    

知识点:了解 selenium使用代理ip

8. selenium替换user-agent

selenium控制谷歌浏览器时,User-Agent默认是谷歌浏览器的,这一小节我们就来学习使用不同的User-Agent

  • 替换user-agent的方法

    • 实例化配置对象
      • options = webdriver.ChromeOptions()
    • 配置对象添加替换UA的命令
      • options.add_argument('--user-agent=Mozilla/5.0 HAHA')
    • 实例化带有配置对象的driver对象
      • driver = webdriver.Chrome('./chromedriver', chrome_options=options)
  • 参考代码如下:

    from selenium import webdriver
    
    options = webdriver.ChromeOptions() # 创建一个配置对象
    options.add_argument('--user-agent=Mozilla/5.0 HAHA') # 替换User-Agent
    
    driver = webdriver.Chrome('./chromedriver', chrome_options=options)
    
    driver.get('http://www.itcast.cn')
    print(driver.title)
    driver.quit()
    

知识点:了解 selenium替换user-agent

常见的反爬手段和解决思路

学习目标
  1. 了解 服务器反爬的原因
  2. 了解 服务器常反什么样的爬虫
  3. 了解 反爬虫领域常见的一些概念
  4. 了解 反爬的三个方向
  5. 了解 常见基于身份识别进行反爬
  6. 了解 常见基于爬虫行为进行反爬
  7. 了解 常见基于数据加密进行反爬

1 服务器反爬的原因

  • 爬虫占总PV(PV是指页面的访问次数,每打开或刷新一次页面,就算做一个pv)比例较高,这样浪费钱(尤其是三月份爬虫)。

    三月份爬虫是个什么概念呢?每年的三月份我们会迎接一次爬虫高峰期,有大量的硕士在写论文的时候会选择爬取一些往网站,并进行舆情分析。因为五月份交论文,所以嘛,大家都是读过书的,你们懂的,前期各种DotA,LOL,到了三月份了,来不及了,赶紧抓数据,四月份分析一下,五月份交论文,就是这么个节奏。

  • 公司可免费查询的资源被批量抓走,丧失竞争力,这样少赚钱。

    数据可以在非登录状态下直接被查询。如果强制登陆,那么可以通过封杀账号的方式让对方付出代价,这也是很多网站的做法。但是不强制对方登录。那么如果没有反爬虫,对方就可以批量复制的信息,公司竞争力就会大大减少。竞争对手可以抓到数据,时间长了用户就会知道,只需要去竞争对手那里就可以了,没必要来我们网站,这对我们是不利的。

  • 状告爬虫成功的几率小

    爬虫在国内还是个擦边球,就是有可能可以起诉成功,也可能完全无效。所以还是需要用技术手段来做最后的保障。

2 服务器常反什么样的爬虫

  • 十分低级的应届毕业生

    应届毕业生的爬虫通常简单粗暴,根本不管服务器压力,加上人数不可预测,很容易把站点弄挂。

  • 十分低级的创业小公司

    现在的创业公司越来越多,也不知道是被谁忽悠的然后大家创业了发现不知道干什么好,觉得大数据比较热,就开始做大数据。分析程序全写差不多了,发现自己手头没有数据。怎么办?写爬虫爬啊。于是就有了不计其数的小爬虫,出于公司生死存亡的考虑,不断爬取数据。

  • 不小心写错了没人去停止的失控小爬虫

    有些网站已经做了相应的反爬,但是爬虫依然孜孜不倦地爬取。什么意思呢?就是说,他们根本爬不到任何数据,除了httpcode是200以外,一切都是不对的,可是爬虫依然不停止这个很可能就是一些托管在某些服务器上的小爬虫,已经无人认领了,依然在辛勤地工作着。

  • 成型的商业对手

    这个是最大的对手,他们有技术,有钱,要什么有什么,如果和你死磕,你就只能硬着头皮和他死磕。

  • 抽风的搜索引擎

    大家不要以为搜索引擎都是好人,他们也有抽风的时候,而且一抽风就会导致服务器性能下降,请求量跟网络攻击没什么区别。

3 反爬虫领域常见的一些概念

因为反爬虫暂时是个较新的领域,因此有些定义要自己下:

  • 爬虫:使用任何技术手段,批量获取网站信息的一种方式。关键在于批量。

  • 反爬虫:使用任何技术手段,阻止别人批量获取自己网站信息的一种方式。关键也在于批量。

  • 误伤:在反爬虫的过程中,错误的将普通用户识别为爬虫。误伤率高的反爬虫策略,效果再好也不能用。

  • 拦截:成功地阻止爬虫访问。这里会有拦截率的概念。通常来说,拦截率越高的反爬虫策略,误伤的可能性就越高。因此需要做个权衡。

  • 资源:机器成本与人力成本的总和。

这里要切记,人力成本也是资源,而且比机器更重要。因为,根据摩尔定律,机器越来越便宜。而根据IT行业的发展趋势,程序员工资越来越贵。因此,通常服务器反爬就是让爬虫工程师加班才是王道,机器成本并不是特别值钱。

4 反爬的三个方向

  • 基于身份识别进行反爬

  • 基于爬虫行为进行反爬

  • 基于数据加密进行反爬

5 常见基于身份识别进行反爬

1 通过headers字段来反爬

headers中有很多字段,这些字段都有可能会被对方服务器拿过来进行判断是否为爬虫

1.1 通过headers中的User-Agent字段来反爬

  • 反爬原理:爬虫默认情况下没有User-Agent,而是使用模块默认设置
  • 解决方法:请求之前添加User-Agent即可;更好的方式是使用User-Agent池来解决(收集一堆User-Agent的方式,或者是随机生成User-Agent)

1.2 通过referer字段或者是其他字段来反爬

  • 反爬原理:爬虫默认情况下不会带上referer字段,服务器端通过判断请求发起的源头,以此判断请求是否合法
  • 解决方法:添加referer字段

1.3 通过cookie来反爬

  • 反爬原因:通过检查cookies来查看发起请求的用户是否具备相应权限,以此来进行反爬
  • 解决方案:进行模拟登陆,成功获取cookies之后在进行数据爬取

2 通过请求参数来反爬

请求参数的获取方法有很多,向服务器发送请求,很多时候需要携带请求参数,通常服务器端可以通过检查请求参数是否正确来判断是否为爬虫

2.1 通过从html静态文件中获取请求数据(github登录数据)

  • 反爬原因:通过增加获取请求参数的难度进行反爬
  • 解决方案:仔细分析抓包得到的每一个包,搞清楚请求之间的联系

2.2 通过发送请求获取请求数据

  • 反爬原因:通过增加获取请求参数的难度进行反爬
  • 解决方案:仔细分析抓包得到的每一个包,搞清楚请求之间的联系,搞清楚请求参数的来源

2.3 通过js生成请求参数

  • 反爬原理:js生成了请求参数
  • 解决方法:分析js,观察加密的实现过程,通过js2py获取js的执行结果,或者使用selenium来实现

2.4 通过验证码来反爬

  • 反爬原理:对方服务器通过弹出验证码强制验证用户浏览行为
  • 解决方法:打码平台或者是机器学习的方法识别验证码,其中打码平台廉价易用,更值得推荐

6 常见基于爬虫行为进行反爬

1 基于请求频率或总请求数量

爬虫的行为与普通用户有着明显的区别,爬虫的请求频率与请求次数要远高于普通用户

1.1 通过请求ip/账号单位时间内总请求数量进行反爬

  • 反爬原理:正常浏览器请求网站,速度不会太快,同一个ip/账号大量请求了对方服务器,有更大的可能性会被识别为爬虫
  • 解决方法:对应的通过购买高质量的ip的方式能够解决问题/购买个多账号

1.2 通过同一ip/账号请求之间的间隔进行反爬

  • 反爬原理:正常人操作浏览器浏览网站,请求之间的时间间隔是随机的,而爬虫前后两个请求之间时间间隔通常比较固定同时时间间隔较短,因此可以用来做反爬
  • 解决方法:请求之间进行随机等待,模拟真实用户操作,在添加时间间隔后,为了能够高速获取数据,尽量使用代理池,如果是账号,则将账号请求之间设置随机休眠

1.3 通过对请求ip/账号每天请求次数设置阈值进行反爬

  • 反爬原理:正常的浏览行为,其一天的请求次数是有限的,通常超过某一个值,服务器就会拒绝响应
  • 解决方法:对应的通过购买高质量的ip的方法/多账号,同时设置请求间随机休眠

2 根据爬取行为进行反爬,通常在爬取步骤上做分析

2.1 通过js实现跳转来反爬

  • 反爬原理:js实现页面跳转,无法在源码中获取下一页url
  • 解决方法: 多次抓包获取条状url,分析规律

2.2 通过蜜罐(陷阱)获取爬虫ip(或者代理ip),进行反爬

  • 反爬原理:在爬虫获取链接进行请求的过程中,爬虫会根据正则,xpath,css等方式进行后续链接的提取,此时服务器端可以设置一个陷阱url,会被提取规则获取,但是正常用户无法获取,这样就能有效的区分爬虫和正常用户
  • 解决方法: 完成爬虫的编写之后,使用代理批量爬取测试/仔细分析响应内容结构,找出页面中存在的陷阱

2.3 通过假数据反爬

  • 反爬原理:向返回的响应中添加假数据污染数据库,通常家属剧不会被正常用户看到
  • 解决方法: 长期运行,核对数据库中数据同实际页面中数据对应情况,如果存在问题/仔细分析响应内容

2.4 阻塞任务队列

  • 反爬原理:通过生成大量垃圾url,从而阻塞任务队列,降低爬虫的实际工作效率
  • 解决方法: 观察运行过程中请求响应状态/仔细分析源码获取垃圾url生成规则,对URL进行过滤

2.5 阻塞网络IO

  • 反爬原理:发送请求获取响应的过程实际上就是下载的过程,在任务队列中混入一个大文件的url,当爬虫在进行该请求时将会占用网络io,如果是有多线程则会占用线程
  • 解决方法: 观察爬虫运行状态/多线程对请求线程计时/发送请求钱

2.6 运维平台综合审计

  • 反爬原理:通过运维平台进行综合管理,通常采用复合型反爬虫策略,多种手段同时使用
  • 解决方法: 仔细观察分析,长期运行测试目标网站,检查数据采集速度,多方面处理

7 常见基于数据加密进行反爬

1 对响应中含有的数据进行特殊化处理

通常的特殊化处理主要指的就是css数据偏移/自定义字体/数据加密/数据图片/特殊编码格式等

1.1 通过自定义字体来反爬
下图来自猫眼电影电脑版

  • 反爬思路: 使用自有字体文件
  • 解决思路:切换到手机版/解析字体文件进行翻译

1.2 通过css来反爬
下图来自猫眼去哪儿电脑版

  • 反爬思路:源码数据不为真正数据,需要通过css位移才能产生真正数据
  • 解决思路:计算css的偏移

1.3 通过js动态生成数据进行反爬

  • 反爬原理:通过js动态生成
  • 解决思路:解析关键js,获得数据生成流程,模拟生成数据

1.4 通过数据图片化反爬

  • 58同城短租](https://baise.58.com/duanzu/38018718834984x.shtml)
  • 解决思路:通过使用图片解析引擎从图片中解析数据

1.5 通过编码格式进行反爬

  • 反爬原理: 不适用默认编码格式,在获取响应之后通常爬虫使用utf-8格式进行解码,此时解码结果将会是乱码或者报错
  • 解决思路:根据源码进行多格式解码,或者真正的解码格式

小结

  • 掌握 常见的反爬手段、原理以及应对思路

验证码处理

学习目标
  1. 了解 验证码的相关知识
  2. 掌握 图片识别引擎的使用
  3. 了解 常见的打码平台
  4. 掌握 通过打码平台处理验证码的方法

1.图片验证码

1.1 什么是图片验证码

  • 验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的公共全自动程序。

1.2 验证码的作用

  • 防止恶意破解密码、刷票、论坛灌水、刷页。有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登录尝试,实际上使用验证码是现在很多网站通行的方式(比如招商银行的网上个人银行,百度社区),我们利用比较简易的方式实现了这个功能。虽然登录麻烦一点,但是对网友的密码安全来说这个功能还是很有必要,也很重要。

1.3 图片验证码在爬虫中的使用场景

  • 注册
  • 登录
  • 频繁发送请求时,服务器弹出验证码进行验证

1.4 图片验证码的处理方案

  • 手动输入(input)
    这种方法仅限于登录一次就可持续使用的情况
  • 图像识别引擎解析
    使用光学识别引擎处理图片中的数据,目前常用于图片数据提取,较少用于验证码处理
  • 打码平台
    爬虫常用的验证码解决方案

2.图片识别引擎

OCR(Optical Character Recognition)是指使用扫描仪或数码相机对文本资料进行扫描成图像文件,然后对图像文件进行分析处理,自动识别获取文字信息及版面信息的软件。

2.1 什么是tesseract

  • Tesseract,一款由HP实验室开发由Google维护的开源OCR引擎,特点是开源,免费,支持多语言,多平台。
  • 项目地址:https://github.com/tesseract-ocr/tesseract

2.2 图片识别引擎环境的安装

1 引擎的安装

  • mac环境下直接执行命令
brew install --with-training-tools tesseract
  • windows环境下的安装
    可以通过exe安装包安装,下载地址可以从GitHub项目中的wiki找到。安装完成后记得将Tesseract 执行文件的目录加入到PATH中,方便后续调用。

  • linux环境下的安装

sudo apt-get install tesseract-ocr

2 Python库的安装

# PIL用于打开图片文件
pip/pip3 install pillow

# pytesseract模块用于从图片中解析数据
pip/pip3 install pytesseract

2.3 图片识别引擎的使用

  • 通过pytesseract模块的 image_to_string 方法就能将打开的图片文件中的数据提取成字符串数据,具体方法如下
from PIL import Image
import pytesseract

im = Image.open()

result = pytesseract.image_to_string(im)

print(result)

2.4 图片识别引擎的使用扩展

  • tesseract简单使用与训练
  • 其他ocr平台
    微软Azure 图像识别:https://azure.microsoft.com/zh-cn/services/cognitive-services/computer-vision/
    有道智云文字识别:http://aidemo.youdao.com/ocrdemo
    阿里云图文识别:https://www.aliyun.com/product/cdi/
    腾讯OCR文字识别:https://cloud.tencent.com/product/ocr

相关文章