爬虫04 /asyncio、selenium规避检测、动作链、无头浏览器

1. 协程asyncio

  • 协程基础

    • 特殊的函数

      • 就是async关键字修饰的一个函数的定义

      • 特殊之处:

        特殊函数被调用后会返回一个协程对象

        特殊函数调用后内部的程序语句没有被立即执行

    • 协程

      • 对象。协程==特殊的函数。协程表示的就是一组特定的操作。
    • 任务对象

      • 高级的协程(对协程的进一步的封装)/任务对象表示一组指定的操作

        任务对象协程特殊的函数

        任务对象==特殊的函数

      • 绑定回调/一般用于解析:

        task.add_done_callback(task)

        参数task:当前回调函数对应的任务对象

        task.result():返回的就是任务对象对应的特殊函数的返回值

    • 事件循环对象

      • 创建事件循环对象
      • 将任务对象注册到该对象中并且开启该对象
      • 作用:loop可以将其内部注册的所有的任务对象进行异步执行
    • 代码示例:

    import asyncio
    from time import sleep # 特殊的函数
    async def get_request(url):
    print('正在下载:',url)
    sleep(2)
    print('下载完毕:',url) return 'page_text'
    # 回调函数的定义(普通的函数)
    def parse(task):
    # 参数表示的就是任务对象
    print('i am callback!!!',task.result()) # 特殊函数的调用
    c = get_request('www.lbzhk.com') # 创建一个任务对象
    task = asyncio.ensure_future(c)
    # 给任务对象绑定一个回调函数
    task.add_done_callback(parse) # 创建一个事件循环对象
    loop = asyncio.get_event_loop()
    # 将任务对象注册到该对象中并且开启该对象
    loop.run_until_complete(task) # 让loop执行了一个任务
  • 多任务协程

    • 挂起:就是交出cpu的使用权。

      wait(tasks):给每个任务对象赋予一个可被挂起的的权限

    • await:被用作特殊函数内部(被阻塞)

    • 代码示例:

    import asyncio
    from time import sleep
    import time
    # 特殊的函数
    async def get_request(url):
    print('正在下载:',url)
    await asyncio.sleep(2)
    print('下载完毕:',url)
    return 'i am page_text!!!' def parse(task):
    page_text = task.result()
    print(page_text) start = time.time()
    urls = ['www.1.com','www.2.com','www.3.com'] tasks = [] # 存储的是所有的任务对象。多任务!
    for url in urls:
    c = get_request(url)
    task = asyncio.ensure_future(c)
    task.add_done_callback(parse)
    tasks.append(task) loop = asyncio.get_event_loop()
    # asyncio.wait(tasks):给每一个任务对象赋予一个可被挂起的权限
    loop.run_until_complete(asyncio.wait(tasks)) print('总耗时:',time.time()-start)

2. aiohttp多任务异步爬虫

  • 实现异步爬取的条件

    • 不能在特殊函数内部出现不支持异步的模块代码,否则会中断整个的异步效果
    • requests模块不支持异步
    • aiohttp是一个支持异步的网络请求模块
  • 使用aiohttp模块实现多任务异步爬虫的流程

    • 环境安装

      pip install aiohttp
    • 编码流程:

      大致的架构:

      with aiohttp.ClientSession() as s:
      # s.get(url,headers,params,proxy="http://ip:port")
      with s.get(url) as response:
      # response.read()二进制/相当于requests的.content
      page_text = response.text()
      return page_text

      细节补充:

      1. 在每一个with前加上async,标记是一个特殊函数
      2. 需要在每一个阻塞操作前加上await
      async with aiohttp.ClientSession() as s:
      # s.get(url,headers,params,proxy="http://ip:port")
      async with await s.get(url) as response:
      # response.read()二进制(.content)
      page_text = await response.text()
      return page_text
  • 代码示例:

    import asyncio
    import aiohttp
    import time
    from bs4 import BeautifulSoup
    # 将被请求的url全部整合到一个列表中
    urls = ['http://127.0.0.1:5000/bobo','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom']
    start = time.time() async def get_request(url):
    async with aiohttp.ClientSession() as s:
    # s.get(url,headers,params,proxy="http://ip:port")
    async with await s.get(url) as response:
    # response.read()二进制(.content)
    page_text = await response.text()
    return page_text def parse(task):
    page_text = task.result()
    soup = BeautifulSoup(page_text,'lxml')
    data = soup.find('div',class_="tang").text
    print(data)
    tasks = []
    for url in urls:
    c = get_request(url)
    task = asyncio.ensure_future(c)
    task.add_done_callback(parse)
    tasks.append(task) loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks)) print('总耗时:',time.time()-start)

3. selenium的使用

  • selenium和爬虫之间的关联:

    • 模拟登录

    • 便捷的捕获到动态加载的数据

      特点:可见及可得

      缺点:效率低

  • selenium概念/安装

    • 概念:基于浏览器自动化的一个模块。

    • 环境的安装:

      pip install selenium
  • selenium的具体使用

    准备浏览器的驱动程序:http://chromedriver.storage.googleapis.com/index.html

  • selenium演示程序

    from selenium import webdriver
    from time import sleep # 后面是你的浏览器驱动位置,记得前面加r'','r'是防止字符转义的
    driver = webdriver.Chrome(r'chromedriver')
    # 用get打开百度页面
    driver.get("http://www.baidu.com")
    # 查找页面的“设置”选项,并进行点击
    driver.find_elements_by_link_text('设置')[0].click()
    sleep(2)
    # 打开设置后找到“搜索设置”选项,设置为每页显示50条
    driver.find_elements_by_link_text('搜索设置')[0].click()
    sleep(2) # 选中每页显示50条
    m = driver.find_element_by_id('nr')
    sleep(2)
    m.find_element_by_xpath('//*[@id="nr"]/option[3]').click()
    m.find_element_by_xpath('.//option[3]').click()
    sleep(2) # 点击保存设置
    driver.find_elements_by_class_name("prefpanelgo")[0].click()
    sleep(2) # 处理弹出的警告页面 确定accept() 和 取消dismiss()
    driver.switch_to_alert().accept()
    sleep(2)
    # 找到百度的输入框,并输入 美女
    driver.find_element_by_id('kw').send_keys('美女')
    sleep(2)
    # 点击搜索按钮
    driver.find_element_by_id('su').click()
    sleep(2)
    # 在打开的页面中找到“Selenium - 开源中国社区”,并打开这个页面
    driver.find_elements_by_link_text('美女_百度图片')[0].click()
    sleep(3) # 关闭浏览器
    driver.quit()
  • selenium基本使用指令

    from selenium import webdriver
    bro = webdriver.Chrome(executable_path='./chromedriver.exe') # 请求的发送:
    bro.get(url) # 标签定位
    # 使用xpath定位
    search = bro.find_element_by_xpath('//input[@id="key"]')
    # 使用id定位
    search = bro.find_element_by_id('key')
    # 使用class类值定位
    search = bro.find_elements_by_class_name('prefpanelgo') # 向指定标签中录入文本数据
    search.send_keys('mac pro')
    # 模拟点击
    search.click()
    # JS注入
    bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    # 处理弹出的警告页面 确定accept() 和 取消dismiss()
    bro.switch_to_alert().accept()
    # switch_to.frame进行指定子页面的切换
    bro.switch_to.frame('iframeResult') # 捕获到当前页面的数据
    page_text = bro.page_source
    # 保留当前页面截图
    bro.save_screenshot('123.png') # 关闭浏览器
    bro.quit()
  • selenium简单使用示例代码:

    from selenium import webdriver
    from time import sleep
    # 结合着浏览器的驱动实例化一个浏览器对象
    bro = webdriver.Chrome(executable_path='./chromedriver.exe') # 请求的发送
    url = 'https://www.jd.com/'
    bro.get(url)
    sleep(1)
    # 标签定位
    # bro.find_element_by_xpath('//input[@id="key"]')
    search = bro.find_element_by_id('key')
    search.send_keys('mac pro') # 向指定标签中录入文本数据
    sleep(2)
    btn = bro.find_element_by_xpath('//*[@id="search"]/div/div[2]/button')
    btn.click()
    sleep(2)
    # JS注入
    bro.execute_script('window.scrollTo(0,document.body.scrollHeight)') # 捕获到当前页面的数据
    page_text = bro.page_source
    print(page_text)
    sleep(3) bro.quit()
  • 动态加载数据的捕获代码示例:

    http://125.35.6.84:81/xk/,对药监总局前3页的企业名称进行爬取

    from selenium import webdriver
    from lxml import etree
    from time import sleep
    bro = webdriver.Chrome(executable_path='./chromedriver.exe')
    url = 'http://125.35.6.84:81/xk/'
    bro.get(url)
    page_text = bro.page_source all_page_text = [page_text]
    # 点击下一页
    for i in range(2):
    # 获取标签
    nextPage = bro.find_element_by_xpath('//*[@id="pageIto_next"]')
    # 进行点击
    nextPage.click()
    sleep(1)
    all_page_text.append(bro.page_source) # 对爬取到的数据进行解析
    for page_text in all_page_text:
    tree = etree.HTML(page_text)
    li_list = tree.xpath('//*[@id="gzlist"]/li')
    for li in li_list:
    name = li.xpath('./dl/@title')[0]
    print(name) sleep(2)
    bro.quit()

4. 动作链

  • 动作链概念/使用流程

    • ActionChains,一系列的行为动作

      动作链对象action和浏览器对象bro是独立的

    • 使用流程:

      1. 实例化一个动作链对象,需要将指定的浏览器和动作链对象进行绑定

      2. 执行相关的连续的动作

      3. perform()立即执行动作链制定好的动作

  • 示例代码:

    from selenium import webdriver
    from selenium.webdriver import ActionChains # 动作链
    from time import sleep
    bro = webdriver.Chrome(executable_path='./chromedriver.exe') url = 'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable' bro.get(url)
    # NoSuchElementException:定位的标签是存在与iframe之中,则就会抛出这个错误
    # 解决方法:switch_to.frame进行指定子页面的切换
    bro.switch_to.frame('iframeResult')
    div_tag = bro.find_element_by_xpath('//*[@id="draggable"]') # 实例化一个动作链对象
    action = ActionChains(bro)
    action.click_and_hold(div_tag) # 点击且长按 # perform()让动作链立即执行
    for i in range(5):
    action.move_by_offset(xoffset=15,yoffset=15).perform()
    sleep(2)
    action.release()
    sleep(5)
    bro.quit()

5. 12306模拟登录分析

  • 模拟登录流程:

    1. 将当前浏览器页面进行图片保存
    2. 将验证码的局部区域进行裁剪
      • 捕获标签在页面中的位置信息
      • 裁剪范围对应的矩形区域
      • 使用Image工具进行指定区域的裁剪
    3. 调用打码平台进行验证码的识别/返回对应的坐标位置
  • 代码示例:

    from selenium import webdriver
    from selenium.webdriver import ActionChains
    from time import sleep
    from PIL import Image # 安装PIL或者是Pillow
    from CJY import Chaojiying_Client # 封装一个识别验证码的函数
    def transformCode(imgPath,imgType):
    chaojiying = Chaojiying_Client('bobo328410948', 'bobo328410948', '899370')
    im = open(imgPath, 'rb').read()
    return chaojiying.PostPic(im, imgType)['pic_str'] bro = webdriver.Chrome(executable_path='./chromedriver.exe') bro.get('https://kyfw.12306.cn/otn/login/init')
    sleep(2)
    # 将当前浏览器页面进行图片保存
    bro.save_screenshot('./main.png')
    # 将验证码的局部区域进行裁剪
    # 捕获标签在页面中的位置信息
    img_tag = bro.find_element_by_xpath('//*[@id="loginForm"]/div/ul[2]/li[4]/div/div/div[3]/img')
    location = img_tag.location # 标签的起始位置坐标(左下角坐标)
    size = img_tag.size # 标签的尺寸
    # 裁剪范围对应的矩形区域
    rangle = (int(location['x']),int(location['y']),int(location['x']+size['width']),int(location['y']+size['height']))
    # 使用Image工具进行指定区域的裁剪
    i = Image.open('./main.png')
    frame = i.crop(rangle) # crop就是根据指定的裁剪范围进行图片的截取
    frame.save('code.png') # 调用打码平台进行验证码的识别
    result = transformCode('./code.png',9004)
    print(result) #x1,y1|x2,y2|x3,y3 # x1,y1|x2,y2|x3,y3 ==>[[x1,y1],[x2,y2],[x3,y3]]
    all_list = [] # [[x1,y1],[x2,y2],[x3,y3]]
    if '|' in result:
    list_1 = result.split('|')
    count_1 = len(list_1)
    for i in range(count_1):
    xy_list = []
    x = int(list_1[i].split(',')[0])
    y = int(list_1[i].split(',')[1])
    xy_list.append(x)
    xy_list.append(y)
    all_list.append(xy_list)
    else:
    x = int(result.split(',')[0])
    y = int(result.split(',')[1])
    xy_list = []
    xy_list.append(x)
    xy_list.append(y)
    all_list.append(xy_list) for point in all_list:
    x = point[0]
    y = point[1]
    ActionChains(bro).move_to_element_with_offset(img_tag,x,y).click().perform()
    sleep(1) bro.find_element_by_id('username').send_keys('xxxxxx')
    sleep(1)
    bro.find_element_by_id('password').send_keys('xxxx')
    sleep(1) bro.find_element_by_id('loginSub').click() sleep(10)
    print(bro.page_source)
    bro.quit()

6. selenium规避风险

  • 测试服务器是否有selenium检测机制

    1. 正常打开一个网站进行window.navigator.webdriver的js注入,返回值为undefined
    2. 使用selenium打开的页面,进行上述js注入返回的是true
  • 规避检测代码示例:

    # 规避检测
    from selenium import webdriver
    from selenium.webdriver import ChromeOptions
    option = ChromeOptions()
    option.add_experimental_option('excludeSwitches', ['enable-automation']) bro = webdriver.Chrome(executable_path='./chromedriver.exe',options=option) url = 'https://www.taobao.com/' bro.get(url)

7. 无头浏览器

  • 现有无头浏览器

    • phantomJs
    • 谷歌无头
  • 无头浏览器代码示例:

    # 无头浏览器
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from time import sleep
    chrome_options = Options()
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--disable-gpu') bro = webdriver.Chrome(executable_path='./chromedriver.exe',chrome_options=chrome_options)
    url = 'https://www.taobao.com/'
    bro.get(url)
    sleep(2)
    bro.save_screenshot('123.png') print(bro.page_source)

总结:

  1. 网络请求的模块:requests/urllib/aiohttp

  2. aiohttp和requests的区别:

    • 代理requests用poroxies,aiohttp用的是proxy

    • 接收二进制文件requests用response.content,aiohttp用的是response.read()

爬虫04 /asyncio、selenium规避检测、动作链、无头浏览器的更多相关文章

  1. selenium中动作链的使用

    一.问题 我们有时候在使用selenium的时候,会遇到悬停后点击元素的操作,因此需要一个动作链来完成这个功能. 二.解决 从selenium的包中导入actionchains函数,利用xpath找到 ...

  2. Selenium 动作链

    Selenium 模拟浏览器操作,有一些操作,它们没有特定的执行对象,比如鼠标拖曳.键盘按键等,这些动作用另一种方式来执行,那就是动作链 更多动作链参考官网:https://selenium-pyth ...

  3. selenium动作链

    简介 一般来说我们与页面的交互可以使用Webelement的方法来进行点击等操作. 但是,有时候我们需要一些更复杂的动作,类似于拖动,双击,长按等等. 这时候就需要用到我们的Action Chains ...

  4. selenium处理iframe和动作链

    selenium处理iframe和动作链 iframe iframe就是一个界面里嵌套了其他界面,这个时候selenium是不能从主界面找到子界面的属性,需要先找到子界面,再去找子界面的属性 动作链( ...

  5. selenium之动作链

    概念:一组连续的行为动作 爬取网站:https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable 背景:把左边的方块横竖往下便宜 ...

  6. 爬虫之图片懒加载技术、selenium工具与PhantomJS无头浏览器

    图片懒加载技术 selenium爬虫简单使用 2.1 selenium简介 2.2 selenium安装 2.3 selenium简单使用 2.3.1 selenium使用案例 2.3.2 selen ...

  7. # Python3微博爬虫[requests+pyquery+selenium+mongodb]

    目录 Python3微博爬虫[requests+pyquery+selenium+mongodb] 主要技术 站点分析 程序流程图 编程实现 数据库选择 代理IP测试 模拟登录 获取用户详细信息 获取 ...

  8. 爬虫基础(三)-----selenium模块应用程序

    摆脱穷人思维 <三> :  培养"目标导向"的思维:  好项目永远比钱少,只要目标正确,钱总有办法解决. 一 selenium模块 什么是selenium?seleni ...

  9. 爬虫----爬虫请求库selenium

    一 介绍 selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题 selenium本质是通过驱动浏览器,完全模拟浏览器的操作, ...

随机推荐

  1. 在VisualStudio中为GUI程序添加console

    1.使用WINDOWS提供的一系列ReadConsole,WriteConsole等API来完成这个功能,具体参见MSDN HANDLE hOut = GetStdHandle(STD_OUTPUT_ ...

  2. [每日一题2020.06.17] leetcode周赛T3 5438 制作m束花所需的最少天数 二分搜索

    题目链接 这题我开始一直在想如何在数组上dp操作搜索区间, 很蠢, 实际上用二分查找的方法可以很快的解决 首先我们通过一个函数判断第x天是否符合题意, 如果x天可以做出m束花, 那么大于m的天数必然可 ...

  3. C++值元编程

    --永远不要在OJ上使用值元编程,过于简单的没有优势,能有优势的编译错误. 背景 2019年10月,我在学习算法.有一道作业题,输入规模很小,可以用打表法解决.具体方案有以下三种: 运行时预处理,生成 ...

  4. Linux 之Mycat搭建报错 java.net.MalformedURLException: Local host name unknown: java.net.UnknownHostException

    搭建MyCat环境时出现 错误: 代理抛出异常错误: java.net.MalformedURLException: Local host name unknown: java.net.Unknown ...

  5. idea安装docker插件

    Preferences->Plugins 根据上图安装docker插件,安装完成后可使用idea来管理docker项目了.docker运行项目请参加"Docker开发环境搭建" ...

  6. git和github入门指南(3.1)

    3.远程管理 3.1.远程仓库相关命令 1.查看远程仓库名字,这里以github为例 git remote 上面命令执行后会得到:origin,这样一个名字,这个名字是我们克隆的时候默认设置好的 如果 ...

  7. 解密TaurusDB存储端高并发之线程池

    摘要:为了能加快相关任务的高效执行,TaurusDB采用多线程技术处理的方式,增加处理器单元的吞吐能力,从而提高存储端的执行效率. 1. TaurusDB背景 随着云计算进入2.0时代,数据急剧膨胀, ...

  8. linux下 解释 终端命令 ls -al或者ls -li 输出的信息

    $ ls -al            drwxr-xr-x.            wjshan0808    wjshan0808        Sep :    .cache $ ls -li ...

  9. Java 内存分析之mat安装

    有三款内存分析的工具 免费 VisualVM MAT 下载地址https://www.eclipse.org/mat/ mac 下面 under the current working directo ...

  10. (私人收藏)python学习(游戏、爬虫、排序、练习题、错误总结)

    python学习(游戏.爬虫.排序.练习题.错误总结) https://pan.baidu.com/s/1dPzSoZdULHElKvb57kuKSgl7bz python100经典练习题python ...