关于爬虫(Part Two)

目录

一、爬虫之验证码

1、输入式验证码

2、滑动式验证码

3、点击式验证码 

二、爬虫之动态加载数据处理——selenium模块

1、基本介绍

2、使用流程

3、定位元素的方式

4、实例

三、 Scrapy框架

1、概述

2、基本构成

3、基本流程


一、爬虫之验证码

       当我们在遇到需要登陆或者注册的网站时就会遇到验证码,验证码的出现就是为了区分人和机器,但是随着现在人工智能的发展,这种区分已经不明确了,在python中有PIL库进行图像处理、机器学习也能更好地解决验证码的问题,下面结合实例列举爬虫如何让应对验证码问题;

1、输入式验证码

类型:用户根据图片输入相应的数字和字母

应对:用Python的第三方库Tesserocr-OCR,对网页上的验证码图片进行识别

from PIL import Image
import tesserocr
image = Image.open('./1.png')
result = tesserocr.image_to_text(image)
print(result)

当该图片的背景对图上数字形成干扰易造成识别误差时应对图片转灰度再进行二值化处理,以此提高识别率:

image = Image.open('./1.png')
image.show()
image = image.convert('L')
threshold = 127
table = []
for i in range(256):
    if i < threshold:
        table.append(0)
    else:
        table.append(1)
image = image.point(table,'1')
image.show()
result = tesserocr.image_to_text(image)
print(result)

 2、滑动式验证码

       如Bilibili视频网站用户登录界面,在输入完密码后需要滑动进行拼图验证。解决思路是存三张图片,分别是完整的图、有缺口的图和缺口图。首先识别缺口在图中的位置,然后计算滑动的距离和轨迹。最后用selenium进行模拟操作。

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
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
import time
import random
 
from PIL import Image
 
web='http://literallycanvas.com/'
 
#初始化
def init():
    #定义全局变量
    global url, browser, username, password, wait
    url = 'https://passport.bilibili.com/login'
    browser = webdriver.Chrome()
    username = '************'
    password = '************'
    wait = WebDriverWait(browser, 20)
    
#登录
def login():
    browser.get(url)
    user = wait.until(EC.presence_of_element_located((By.ID, 'login-username')))
    passwd = wait.until(EC.presence_of_element_located((By.ID, 'login-passwd')))
    user.send_keys(username)
    passwd.send_keys(password)
    #通过输入回车键模仿用户登录
    #passwd.send_keys(Keys.ENTER)
    login_btn=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'a.btn.btn-login')))
    #随机延时点击
    time.sleep(random.random()*3)
    login_btn.click()
 
#设置元素的可见性用于截图
def show_element(element):
    browser.execute_script("arguments[0].style = arguments[1]", element, "display: block;")
def hide_element(element):
    browser.execute_script("arguments[0].style = arguments[1]", element, "display: none;")
 
#截图
def save_pic(obj, name):
    try:
        pic_url = browser.save_screenshot('.\\bilibili.png')
        #开始获取元素位置信息
        left = obj.location['x']
        top = obj.location['y']
        right = left + obj.size['width']
        bottom = top + obj.size['height']
        
        im = Image.open('.\\bilibili.png')
        im = im.crop((left, top, right, bottom))
        file_name = 'bili' + name + '.png'
        im.save(file_name)
    except BaseException as msg:
        print("截图失败:%s" % msg)
 
def cut():
    c_background = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'canvas.geetest_canvas_bg.geetest_absolute')))
    c_slice = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'canvas.geetest_canvas_slice.geetest_absolute')))
    c_full_bg = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'canvas.geetest_canvas_fullbg.geetest_fade.geetest_absolute')))
    hide_element(c_slice)
    save_pic(c_background, 'back')
    show_element(c_slice)
    save_pic(c_slice, 'slice')
    show_element(c_full_bg)
    save_pic(c_full_bg, 'full')
    
#判断元素是否相同
def is_pixel_equal(bg_image, fullbg_image, x, y):
    #bg_image是缺口的图片
    #fullbg_image是完整图片
    bg_pixel = bg_image.load()[x, y]
    fullbg_pixel = fullbg_image.load()[x, y]
    threshold = 60
    if (abs(bg_pixel[0] - fullbg_pixel[0] < threshold) and abs(bg_pixel[1] - fullbg_pixel[1] < threshold) and abs(bg_pixel[2] - fullbg_pixel[2] < threshold)):
        return True
    else:
        return False
    
#计算滑块移动的距离
def get_distance(bg_image, fullbg_image):
    distance = 57
    for i in range(distance, fullbg_image.size[0]):
        for j in range(fullbg_image.size[1]):
            if not is_pixel_equal(fullbg_image, bg_image, i, j):
                return i
 
#构造滑动轨迹
def get_trace(distance):
    #distance是缺口离滑块的距离
    trace = []
    faster_distance = distance*(4/5)
    start, v0, t = 0, 0, 0.2
    while start < distance:
        if start < faster_distance:
            a = 1.5
        else:
            a = -3
        move = v0 * t + 1 / 2 * a * t * t
        v = v0 + a * t
        v0 = v
        start += move
        trace.append(round(move))
    return trace
 
#模拟拖动
def move_to_gap(trace):
    slider=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'div.geetest_slider_button')))
    # 使用click_and_hold()方法悬停在滑块上,perform()方法用于执行
    ActionChains(browser).click_and_hold(slider).perform()
    for x in trace:
        # 使用move_by_offset()方法拖动滑块,perform()方法用于执行
        ActionChains(browser).move_by_offset(xoffset=x, yoffset=0).perform()
    time.sleep(0.5)
    ActionChains(browser).release().perform()
    
def slide():
    distance=get_distance(Image.open('.\\bili_back.png'),Image.open('.\\bili_full.png'))
    trace = get_trace(distance-5)
    move_to_gap(trace)
    time.sleep(3)
 
init()
login()
cut()
slide()

3、点击式验证码 

类型:按照给定的顺序依次点击完成验证

应对:调用第三方识别库——获取第三方返回的坐标——用selenium模拟用户点击。如付费软件超级鹰。代码分为两个部分,一个是超级鹰API接口,另一个是上述操作。

import time
 
from PIL import Image
from  selenium import webdriver
from selenium.webdriver import ActionChains
 
 
def crack():
 
    # 保存网页截图
    browser.save_screenshot('222.jpg')
 
    # 获取 验证码确定按钮
    button = browser.find_element_by_xpath(xpath='//div[@class="geetest_panel"]/a/div')
 
    #  获取 验证码图片的 位置信息
    img1 = browser.find_element_by_xpath(xpath='//div[@class="geetest_widget"]')
    location = img1.location
    size = img1.size
    top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size[
        'width']
    print('图片的宽:', img1.size['width'])
    print(top, bottom, left, right)
 
    #  根据获取的验证码位置信息和网页图片  对验证码图片进行裁剪 保存
    img_1 = Image.open('222.jpg')
    capcha1 = img_1.crop((left, top, right, bottom-54))
    capcha1.save('tu1-1.png')
 
    # 接入超级鹰 API 获取图片中的一些参数 (返回的是一个字典)
    cjy = Chaojiying('*********', '************', '900751')
    im = open('tu1-1.png', 'rb').read()
    content = cjy.post_pic(im, 9004)
    print(content)
    #  将图片中汉字的坐标位置 提取出来
    positions = content.get('pic_str').split('|')
    locations = [[int(number)for number in group.split(",")] for group in positions]
    print(positions)
    print(locations)
 
    #  根据获取的坐标信息 模仿鼠标点击验证码图片
    for location1 in locations:
        print(location1)
        ActionChains(browser).move_to_element_with_offset(img1 , location1[0],location1[1]).click().perform()
        time.sleep(1)
    button.click()
    time.sleep(1)
    # 失败后重试
    lower = browser.find_element_by_xpath('//div[@class="geetest_table_box"]/div[2]').text
    print('判断', lower)
    if  lower != '验证失败 请按提示重新操作'and lower != None:
        print('登录成功')
        time.sleep(3)
    else:
        time.sleep(3)
        print('登录失败')
        # 登录失败后 , 调用 该函数 , 后台 则对该次判断不做扣分处理
        pic_id = content.get('pic_id')
        print('图片id为:',pic_id)
        cjy = Chaojiying('********', '**********', '900751')
        cjy.report_error(pic_id)
        crack()
 
if __name__ == '__main__':
    patn = 'chromedriver.exe'
    browser = webdriver.Chrome(patn)
 
    browser.get('https://www.jianshu.com/sign_in')
    browser.save_screenshot('lodin.png')
 
    # 填写from表单 点击登陆  获取验证码 的网页截图
    login = browser.find_element_by_id('sign-in-form-submit-btn')
    username = browser.find_element_by_id('session_email_or_mobile_number')
    password = browser.find_element_by_id('session_password')
    username.send_keys('***********')
    password.send_keys('***********')
    login.click()
    time.sleep(5)
    crack()
 

二、爬虫之动态加载数据处理——selenium模块

1、基本介绍

        selenium主要是用来做自动化测试,支持多种浏览器,爬虫中主要用来解决JavaScript渲染问题。模拟浏览器进行网页加载,当requests,urllib无法正常获取网页内容的时候,是网页自动化测试工具,可以自动化的操作浏览器。如果需要操作哪个浏览器需要安装对应的driver,比如你需要通过selenium操作chrome,那必须安装chromedriver,而且版本与chrome保持一致。

2、使用流程

    - 下载一个浏览器的驱动程序

    - 实例化一个浏览器对象
    - 编写基于浏览器自动化的操作代码
        - 发起请求:get(url)
        - 标签定位:find系列的方法
        - 标签交互:send_keys('xxx')
        - 执行js程序:excute_script('jsCode')
        - 前进,后退:back(),forward()
        - 关闭浏览器:quit()

3、定位元素的方式

  1. id
  2. name
  3. class name
  4. tag name
  5. link text
  6. partial link text
  7. xpath
  8. css selector

关于爬虫(Part Two)_第1张图片

4、实例

        如 我们需要通过前端工具来查看网页元素属性: