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

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 协程

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图片懒加载

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 homework\day105\chromedriver.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.实现模拟登陆
  • 基本操作
#步骤:
1.实例化某一款浏览器对象(驱动程序的路径)
2.find系列的函数用于标签定位
  • 浏览器创建
  • 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 homework\day105\chromedriver.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 homework\day105\chromedriver.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()
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 homework\day105\chromedriver.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 homework\day105\chromedriver.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:\Users\oldboy-python\Desktop\爬虫+数据\day04\chromedriver.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+'\n\n\n')
    
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:\Users\Administrator\Desktop\爬虫授课\day05\ziliao\phantomjs-2.1.1-windows\bin\phantomjs.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 homework\day105\chromedriver.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(