• python爬虫入门 之 单线程 + 多任务异步协程


    第五章 .单线程 + 多任务异步协程

    5.1 进程和线程

    • 自己写一个服务端

      from flask import Flask
      import time

      app = Flask(__name__)

      @app.route('/one')
      def index_one():
         time.sleep(2)
         return  "hello one"

      @app.route('/two')
      def index_two():
         time.sleep(2)
         return  "hello two"

      @app.route('/three')
      def index_three():
         time.sleep(2)
         return  "hello three"

      if __name__ == '__main__':
         app.run(threaded=True)
    • 同步代码

      from multiprocessing.dummy import Pool
      import requests
      import time

      start = time.time()
      pool = Pool(3)

      urls = ["http://127.0.0.1:5000/one","http://127.0.0.1:5000/two","http://127.0.0.1:5000/three"]

      for url in urls:
         page_text = requests.get(url,).text
         print(page_text)
      print('总耗时:',time.time()-start)

    • 异步代码

      from multiprocessing.dummy import Pool
      import requests
      import time

      start = time.time()
      pool = Pool(3)

      urls = ["http://127.0.0.1:5000/one","http://127.0.0.1:5000/two","http://127.0.0.1:5000/three"]

      def get_request(url):
         return requests.get(url).text

      response_list = pool.map(get_request,urls)
      print(response_list)

      #解析
      def parse(page_text):
         print(len(page_text))

      pool.map(parse,response_list)
      print('总耗时:',time.time()-start)
      print('总耗时:',time.time()-start)

    5.2 协程

    • asyncio链接https://www.liaoxuefeng.com/wiki/1016959663602400/1017970488768640

    • 是一个对象,可以将协程当做一个特殊的函数,如果一个函数的定义被 anync 关键字所修饰,该特殊函数被调用后,函数内部的程序语句不会立即执行 ,而是返回一个协程对象

      from time import sleep

      async def get_request(url):
         print('正在请求:',url)
         sleep(2)
         print('请求结束')

      c = get_request("www.baidu.com")
      print(c)    # <coroutine object get_request at 0x000000000A184308>

    5.3任务对象(task)

    • 所谓的任务对象就是对携程对象的进一步封装,在任务对象中可以实现显示协程对象的运行状况,

    • 特点

      • 任务对象最终是要被注册到事件循环对象中的.

      • 回调函数是绑定给任务对象的,只有当任务对象对应的特殊函数被执行完毕后,回调函数才会被执行

    • await 挂起的操作,可理解为交出cpu的使用权

    • 事件循环对象

      • 无限循环的对象,也可以把其当成是某一种容器,该容器中需要放入多个任务对象(就是一组待执行的代码块)

      • 异步的体现 :当事件循环开始后,该对象会按照顺序执行每一个任务对象,当一个任务对象发生阻塞时不会等待,而是直接执行下一个任务对象

      from time import sleep
      import asyncio

      #回调函数
      def callback(task):
         print("i am callback")
         print(task.result())    #result 返回的就是任务对象对应的哪个特殊函数的返回值


      async def get_request(url):
         print('正在请求:',url)
         sleep(2)
         print('请求结束')
         return "hello world"

      #创建一个携程对象
      c = get_request("www.baidu.com")
      #封装一个任务对象
      task = asyncio.ensure_future(c)

      #给任务对象绑定回调函数
      task.add_done_callback(callback)

      #创建一个事件循环对象
      loop = asyncio.get_event_loop()
      #将任务对象注册到事件循环中并且开启了事件循环
      loop.run_until_complete(task)

    5.4多任务异步协程

    #注意事项:
    1.将多个任务对象存储到一个列表中,然后将该列表注册到事件循环中,在注册的过程中,该列表需要被wait方法进行处理
    2.在任务对象对应的特殊函数内部的实现中,不可以出现不支持异步模块的代码,否则就会中断整个的异步效果,并且在该函数的每一阻塞的操作都必须使用await关键字进行修饰
    3.requests模块对应的代码不可以出现在特殊函数内部,因为requests 不支持异步操作
    import time
    import asyncio

    start = time.time()
    urls = [
       "http://127.0.0.1:5000/one",
       "http://127.0.0.1:5000/one",
       "http://127.0.0.1:5000/two",
       "http://127.0.0.1:5000/three"
    ]

    #待执行的代码块中不可以出现不支持异步模块的代码
    #在该函数内部如果有阻塞,阻塞操作必须使用await关键字修饰
    async def get_request(url):
       print('正在请求:',url)
       # await不用不会报错,但不会有异步效果
       await asyncio.sleep(2)
       print('请求结束')
       return "hello world"

    #放置所有的任务对象
    tasks = []
    for url in urls:
       c = get_request(url)
       task = asyncio.ensure_future(c)
       tasks.append(task)

    loop = asyncio.get_event_loop()
    #wait不用会报错
    loop.run_until_complete(asyncio.wait(tasks))
    print("所用时长:",time.time()-start)

    5.4.1在爬虫中使用 多任务异步协程

    import time
    import asyncio
    import requests
    start = time.time()
    urls = [
       "http://127.0.0.1:5000/one",
       "http://127.0.0.1:5000/two",
       "http://127.0.0.1:5000/three"
    ]


    # 无法实现异步的效果,因为requests 不支持异步操作
    async def req(url):
       page_text = await requests.get(url).text
       return page_text


    #构建任务列表
    tasks = []
    for url in urls:
       #协程对象
       c = req(url)
       #任务对象
       task = asyncio.ensure_future(c)
       tasks.append(task)

    #创建事件循环对象
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))
    print(time.time()-start)

    如上图,我们会发现出现了一个错误,我们尝试了解决,发现:
    #无法实现异步的效果,因为requests 不支持异步操作
    所以我们引用了了aiohttp模块

    5.4.2 aiohttp模块

    • 一个支持异步操作的网络请求的模块

    • 环境的安装 pip install aiohttp

    • 记忆步骤:

      第一步: 初步架构

      async def req(url):
      with aiohttp.ClientSession() as s:
      with s.get(url) as response:
      page_text = response.text()
      return page_text

      第二步: 补充细节

      在每一个 with 之前加上 async,在每一步阻塞前加上 await

      async def req(url):
         async with aiohttp.ClientSession() as s:
             async with await s.get(url) as response:
                 page_text = await response.text()
                 return page_text

      server端代码

      from flask import Flask, render_template
      import time

      app = Flask(__name__)

      @app.route('/one')
      def index_one():
         time.sleep(2)
         return  render_template("text.html")

      @app.route('/two')
      def index_two():
         time.sleep(2)
         return  "hello two"

      @app.route('/three')
      def index_three():
         time.sleep(2)
         return  "hello three"

      if __name__ == '__main__':
         app.run(threaded=True)

      客户端代码

      import time
      import asyncio
      import aiohttp
      from lxml import etree

      start = time.time()
      urls = [
         "http://127.0.0.1:5000/one",
         "http://127.0.0.1:5000/two",
         "http://127.0.0.1:5000/three"
      ]


      # 无法实现异步的效果,因为requests 不支持异步操作
      async def req(url):
         async with aiohttp.ClientSession() as s:
             async with await s.get(url) as response:
                 # response.read() 返回 byte 类型的数据
                 # response.text() 返回 字符串
                 page_text = await response.text()
                 return page_text
         # 细节的补充 : 在每一个 with 之前加上 async,在每一步阻塞前加上 await


      def parse(task):
         page_text = task.result()
         tree = etree.HTML(page_text)
         name = tree.xpath("//p/text()")[0]
         print(name)

      #构建任务列表
      tasks = []
      for url in urls:
         #协程对象
         c = req(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)

    第六章 .图片懒加载技术、selenium和PhantomJS

    6.1图片懒加载

    • 案例分析:抓取站长素材http://sc.chinaz.com/中的图片数据

      import requests
      from lxml import etree

      if __name__ == "__main__":
          url = 'http://sc.chinaz.com/tupian/gudianmeinvtupian.html'
          headers = {
              'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
          }
          #获取页面文本数据
          response = requests.get(url=url,headers=headers)
          response.encoding = 'utf-8'
          page_text = response.text
          #解析页面数据(获取页面中的图片链接)
          #创建etree对象
          tree = etree.HTML(page_text)
          div_list = tree.xpath('//div[@id="container"]/div')
          #解析获取图片地址和图片的名称
          for div in div_list:
              image_url = div.xpath('.//img/@src')
              image_name = div.xpath('.//img/@alt')
              print(image_url) #打印图片链接
              print(image_name)#打印图片名称
    • 运行结果观察发现,我们可以获取图片的名称,但是链接获取的为空,检查后发现xpath表达式也没有问题,究其原因出在了哪里呢?

      • 图片懒加载概念:

        • 图片懒加载是一种网页优化技术。图片作为一种网络资源,在被请求时也与普通静态资源一样,将占用网络资源,而一次性将整个页面的所有图片加载完,将大大增加页面的首屏加载时间。为了解决这种问题,通过前后端配合,使图片仅在浏览器当前视窗内出现时才加载该图片,达到减少首屏图片请求数的技术就被称为“图片懒加载”。

    • 网站一般如何实现图片懒加载技术呢?

      • 在网页源码中,在img标签中首先会使用一个“伪属性”(通常使用src2,original......)去存放真正的图片链接而并非是直接存放在src属性中。当图片出现到页面的可视化区域中,会动态将伪属性替换成src属性,完成图片的加载。

    • 站长素材案例后续分析:通过细致观察页面的结构后发现,网页中图片的链接是存储在了src2这个伪属性中

      import requests
      from lxml import etree

      if __name__ == "__main__":
          url = 'http://sc.chinaz.com/tupian/gudianmeinvtupian.html'
          headers = {
              'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
          }
          #获取页面文本数据
          response = requests.get(url=url,headers=headers)
          response.encoding = 'utf-8'
          page_text = response.text
          #解析页面数据(获取页面中的图片链接)
          #创建etree对象
          tree = etree.HTML(page_text)
          div_list = tree.xpath('//div[@id="container"]/div')
          #解析获取图片地址和图片的名称
          for div in div_list:
              image_url = div.xpath('.//img/@src2') #src2伪属性
              image_name = div.xpath('.//img/@alt')
              print(image_url) #打印图片链接
              print(image_name)#打印图片名称

    6.2 selenium

    • 概念: selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题 selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器

    • 环境的安装 : pip install selenium

    • selenium的演示程序

      from selenium import webdriver
      from time import sleep

      # 后面是你的浏览器驱动位置,记得前面加r'','r'是防止字符转义的
      driver = webdriver.Chrome(r'E:after homeworkday105chromedriver.exe')
      # 用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和爬虫之间的关联?

      1.便捷的获取页面中动态加载的数据
      requests模块进行数据爬取,所见非所得
         selenium所见即可得,但速度较慢
      2.实现模拟登陆
    • 基本操作

    • 浏览器创建

      • Selenium支持非常多的浏览器,如Chrome、Firefox、Edge等,还有Android、BlackBerry等手机端的浏览器。另外,也支持无界面浏览器PhantomJS。

        from selenium import webdriver
         
        browser = webdriver.Chrome()
        browser = webdriver.Firefox()
        browser = webdriver.Edge()
        browser = webdriver.PhantomJS()
        browser = webdriver.Safari()
    • 元素定位

      • webdriver 提供了一系列的元素定位方法,常用的有以下几种:

      find_element_by_id()
      find_element_by_name()
      find_element_by_class_name()
      find_element_by_tag_name()
      find_element_by_link_text()
      find_element_by_partial_link_text()
      find_element_by_xpath()
      find_element_by_css_selector()
    • 节点交互

      • Selenium可以驱动浏览器来执行一些操作,也就是说可以让浏览器模拟执行一些动作。比较常见的用法有:输入文字时用send_keys()方法,清空文字时用clear()方法,点击按钮时用click()方法。示例如下:

        from selenium import webdriver
        import time

        browser = webdriver.Chrome()
        browser.get('https://www.taobao.com')
        input = browser.find_element_by_id('q')
        input.send_keys('MAC')
        time.sleep(1)
        input.clear()
        input.send_keys('IPhone')
        button = browser.find_element_by_class_name('btn-search')
        button.click()
        browser.quit()
    • 爬取单页数据

      from selenium import webdriver
      from time import sleep


      #实例化一个浏览器对象
      bro = webdriver.Chrome(executable_path=r'E:after homeworkday105chromedriver.exe')  #executable_path 当前浏览器的驱动程序
      url = "https://www.jd.com/"
      #get 用于发起请求
      bro.get(url)
      #定位指定标签
      search_input = bro.find_element_by_id("key")
      #对指定标签进行数据交互
      search_input.send_keys("macPro")

      btn = bro.find_element_by_xpath('//*[@id="search"]/div/div[2]/button')
      btn.click()

      sleep(2)
      #执行js代码
      jsCode = 'window.scrollTo(0,document.body.scrollHeight)'
      bro.execute_script(jsCode)

      sleep(3)
      bro.quit()
    • 爬取多页数据

      from selenium import webdriver
      from time import sleep
      from lxml import etree


      page_text_list = []
      #实例化一个浏览器对象
      bro = webdriver.Chrome(executable_path=r'E:after homeworkday105chromedriver.exe')  #executable_path 当前浏览器的驱动程序
      url = "http://125.35.6.84:81/xk/"
      #get 用于发起请求
      bro.get(url)

      sleep(2)
      #page_source就是当前浏览器打开页面对应的源码数据
      page_text = bro.page_source
      page_text_list.append(page_text)

      for i in  range(2):
         bro.find_element_by_id('pageIto_next').click()
         sleep(2)
         page_text = bro.page_source
         page_text_list.append(page_text)


      for page_text in page_text_list:
         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(4)
      bro.quit()
    • 动作链 :一系列的行为动作

      地址 https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable

      from selenium import webdriver
      from selenium.webdriver import ActionChains  #动作链
      from time import sleep


      page_text_list = []
      #实例化一个浏览器对象,executable_path 当前浏览器的驱动程序
      bro = webdriver.Chrome(executable_path=r'E:after homeworkday105chromedriver.exe')
      url = "https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable"

      bro.get(url)

      # 如果定位的标签是存在于 iframe 对应的子页面中,在定位标签前一定要进行 switch_to 的操作
      bro.switch_to.frame('iframeResult')   # iframe标签的id
      div_tag = bro.find_element_by_id("draggable")
      # 错误 :selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element:

      #实例化动作链对象
      action = ActionChains(bro)
      #点击且长按
      action.click_and_hold(div_tag)

      #模拟人移动算法(自己百度)

      #这里提供一个简单操作
      for i in range(5):
         # perform :让动作链立即执行
         action.move_by_offset(17,0).perform()
         sleep(0.5)

      #释放动作链
      action.release()
      sleep(3)
      bro.quit()
    • 执行JavaScript

      • 对于某些操作,Selenium API并没有提供。比如,下拉进度条,它可以直接模拟运行JavaScript,此时使用execute_script()方法即可实现,代码如下:

      from selenium import webdriver

      browser = webdriver.Chrome()
      browser.get('https://www.jd.com/')
      browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
      browser.execute_script('alert("123")')
    • 获取页面源码数据

      • 通过page_source属性可以获取网页的源代码,接着就可以使用解析库(如正则表达式、Beautiful Soup、pyquery等)来提取信息了

    • 前进和后退

      • 模拟浏览器的前进后退

      import time
      from selenium import webdriver

      browser=webdriver.Chrome()
      browser.get('https://www.baidu.com')
      browser.get('https://www.taobao.com')
      browser.get('http://www.sina.com.cn/')

      browser.back()
      time.sleep(10)
      browser.forward()
      browser.close()
    • Cookie处理

      • 使用Selenium,还可以方便地对Cookies进行操作,例如获取、添加、删除Cookies等。示例如下:

        from selenium import webdriver

        browser = webdriver.Chrome()
        browser.get('https://www.zhihu.com/explore')
        print(browser.get_cookies())
        browser.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'germey'})
        print(browser.get_cookies())
        browser.delete_all_cookies()
        print(browser.get_cookies())
    • 异常处理

      from selenium import webdriver
      from selenium.common.exceptions import TimeoutException,NoSuchElementException,NoSuchFrameException

      try:
         browser=webdriver.Chrome()
         browser.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
         browser.switch_to.frame('iframssseResult')

      except TimeoutException as e:
         print(e)
      except NoSuchFrameException as e:
         print(e)
      finally:
         browser.close()

    6.3 phantomJS

    • PhantomJS是一款无界面的浏览器,其自动化操作流程和上述操作谷歌浏览器是一致的。由于是无界面的,为了能够展示自动化操作流程,PhantomJS为用户提供了一个截屏的功能,使用save_screenshot函数实现。

    • 无头浏览器 :无可视化界面的浏览器

      • phantomJS

      谷歌无头浏览器

      from selenium import webdriver
      from time import sleep


      from selenium.webdriver.chrome.options import Options

      # 创建一个参数对象,用来控制chrome以无界面模式打开
      chrome_options = Options()
      chrome_options.add_argument('--headless')
      chrome_options.add_argument('--disable-gpu')


      page_text_list = []
      #实例化一个浏览器对象,executable_path 当前浏览器的驱动程序
      bro = webdriver.Chrome(executable_path=r'E:after homeworkday105chromedriver.exe',chrome_options=chrome_options)
      bro.get('https://www.baidu.com')

      sleep(2)

      #截图
      bro.save_screenshot("1.png")

      print(bro.page_source)
      sleep(2)
      bro.quit()
    • selenium规避风险

      可判断为正常用户的正常请求

      执行代码时:

      from selenium import webdriver
      from selenium.webdriver import ChromeOptions
      option = ChromeOptions()
      option.add_experimental_option('excludeSwitches', ['enable-automation'])

      #实例化一个浏览器对象
      bro = webdriver.Chrome(executable_path=r'C:Usersoldboy-pythonDesktop爬虫+数据day04chromedriver.exe',options=option)
      bro.get('https://www.taobao.com/')

    登录qq空间,爬取数据

    import requests
    from selenium import webdriver
    from lxml import etree
    import time

    driver = webdriver.Chrome(executable_path='/Users/bobo/Desktop/chromedriver')
    driver.get('https://qzone.qq.com/')
    #在web 应用中经常会遇到frame 嵌套页面的应用,使用WebDriver 每次只能在一个页面上识别元素,对于frame 嵌套内的页面上的元素,直接定位是定位是定位不到的。这个时候就需要通过switch_to_frame()方法将当前定位的主体切换了frame 里。
    driver.switch_to.frame('login_frame')
    driver.find_element_by_id('switcher_plogin').click()

    #driver.find_element_by_id('u').clear()
    driver.find_element_by_id('u').send_keys('328410948')  #这里填写你的QQ号
    #driver.find_element_by_id('p').clear()
    driver.find_element_by_id('p').send_keys('xxxxxx')  #这里填写你的QQ密码
       
    driver.find_element_by_id('login_button').click()
    time.sleep(2)
    driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    time.sleep(2)
    driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    time.sleep(2)
    driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    time.sleep(2)
    page_text = driver.page_source

    tree = etree.HTML(page_text)
    #执行解析操作
    li_list = tree.xpath('//ul[@id="feed_friend_list"]/li')
    for li in li_list:
       text_list = li.xpath('.//div[@class="f-info"]//text()|.//div[@class="f-info qz_info_cut"]//text()')
       text = ''.join(text_list)
       print(text+' ')
       
    driver.close()

    爬取豆瓣网中的电影信息

    from selenium import webdriver
    from time import sleep
    import time

    if __name__ == '__main__':
       url = 'https://movie.douban.com/typerank?type_name=%E6%81%90%E6%80%96&type=20&interval_id=100:90&action='
       # 发起请求前,可以让url表示的页面动态加载出更多的数据
       path = r'C:UsersAdministratorDesktop爬虫授课day05ziliaophantomjs-2.1.1-windowsinphantomjs.exe'
       # 创建无界面的浏览器对象
       bro = webdriver.PhantomJS(path)
       # 发起url请求
       bro.get(url)
       time.sleep(3)
       # 截图
       bro.save_screenshot('1.png')

       # 执行js代码(让滚动条向下偏移n个像素(作用:动态加载了更多的电影信息))
       js = 'window.scrollTo(0,document.body.scrollHeight)'
       bro.execute_script(js)  # 该函数可以执行一组字符串形式的js代码
       time.sleep(2)

       bro.execute_script(js)  # 该函数可以执行一组字符串形式的js代码
       time.sleep(2)
       bro.save_screenshot('2.png')
       time.sleep(2)
       # 使用爬虫程序爬去当前url中的内容
       html_source = bro.page_source # 该属性可以获取当前浏览器的当前页的源码(html)
       with open('./source.html', 'w', encoding='utf-8') as fp:
           fp.write(html_source)
       bro.quit()

    6.4 基于selenium实现12306模拟登陆

    链接地址 :https://kyfw.12306.cn/otn/login/init

    # ChaoJiYing.py
    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()
    # 12306模拟登陆

    from selenium import webdriver
    from selenium.webdriver import ActionChains
    #Image用作于图片裁剪
    from PIL import Image
    from time import sleep
    from ChaoJiYing import  Chaojiying_Client


    #实例化一个浏览器对象,executable_path 当前浏览器的驱动程序
    bro = webdriver.Chrome(executable_path=r'E:after homeworkday105chromedriver.exe')
    bro.get("https://kyfw.12306.cn/otn/login/init")

    sleep(2)
    #验证码图片的捕获
    bro.save_screenshot("main.png")
    #定位验证码图片对应的标签
    code_img_ele = bro.find_element_by_xpath('//*[@id="loginForm"]/div/ul[2]/li[4]/div/div/div[3]/img')
    #验证码图片基于当前整张页面左上角坐标
    location = code_img_ele.location
    #验证码图片的长和宽
    size = code_img_ele.size

    #裁剪的矩形区域(左下角和右上角两点的坐标)
    rangle = (int(location['x']),int(location['y']),int(location['x']+size['width']),int(location['y']+size['height']))


    i = Image.open('main.png')
    frame = i.crop(rangle)
    frame.save('code.png')

    #使用打码平台进行验证码的识别
    chaojiying = Chaojiying_Client('bobo328410948', 'bobo328410948', '899370') #用户中心>>软件ID 生成一个替换 96001
    im = open('code.png', 'rb').read() #本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
    result = chaojiying.PostPic(im, 9004)['pic_str']
    print(result)  # x1,y1|x2,y2|x3,y3 ==> [[x1,y1],[x2,y2],[x3,y3]]
    all_list = []#[[x1,y1],[x2,y2],[x3,y3]] 每一个列表元素表示一个点的坐标,坐标对应值的0,0点是验证码图片左下角
    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)

    # action = ActionChains(bro)
    for l in all_list:
       x = l[0]
       y = l[1]
       ActionChains(bro).move_to_element_with_offset(code_img_ele,x,y).click().perform()
       sleep(1)

    sleep(3)
    bro.quit()
  • 相关阅读:
    linux将home目录扩容到根目录
    Daily Build
    H公司数据同步的总结
    VB2010新特性之——标识语言版本的新命令行选项/langversion (Visual Basic)
    Linux安装Jemalloc
    Lnmp切换PHP版本
    Server2008通过bat命令自动定时备份MySQL数据库
    IIS 安装AspNetCoreModule托管模块
    JavaScript 学习笔记——Math属性及其方法
    js完美多物体运动框架(缓冲运动)
  • 原文地址:https://www.cnblogs.com/lilinyuan5474/p/11498000.html
Copyright © 2020-2023  润新知