一、单线程+多任务异步协程(推荐)

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

  • 任务对象(task):所谓的任务对象就是对协程对象的进一步封装.在任务对象中可以实现显示协程对象的运行状况. 任务对象最终是需要被注册到事件循环对象中.
  • 绑定回调:回调函数是绑定给任务对象,只有当任务对象对应的特殊函数被执行完毕后,回调函数才会被执行
  • 事件循环对象:无限循环的对象.也可以把其当成是某一种容器.该容器中需要放置多个任务对象(就是一组待执行的代码块).
  • 异步的体现:当事件循环开启后,该对象会安装顺序执行每一个任务对象,当一个任务对象发生了阻塞事件循环是不会等待,而是直接执行下一个任务对象
  • await:挂起的操作.交出cpu的使用权
  • 多任务的异步协程
  • 注意事项:
    • 将多个任务对象存储到一个列表中,然后将该列表注册到事件循环中.在注册的过程中,该列表需要被wait方法进行处理.
    • 在任务对象对应的特殊函数内部的实现中,不可以出现不支持异步模块的代码,否则就会中断整个的 异步效果.并且,在该函数内部每一组阻塞的操作都必须使用await关键字进行修饰.
    • requests模块对应的代码不可以出现在特殊函数内部,因为requests是一个不支持异步的模块
  • aiohttp:支持异步操作的网络请求的模块
  1. 环境安装:pip install aiohttp
  2. 初步的架构:
async def req(url):
  with aiohttp.ClientSessio() as s:
    with s.get(url) as response:
#response.read():byte
      page_text = response.text()
      return page_text
  • 补充细节:在每一个with前面加上async,在每一步的阻塞操作前加上await
async def req(url):
  async with aiohttp.ClientSessio() as s:
    async with await s.get(url) as response:
    #response.read():byte
    page_text = await response.text()
    return page_text

二、selenium

  • 概念:基于浏览器自动化的一个模块.
  • 环境的安装:下载selenium模块
  • selenium和爬虫之间的关联是什么?
    • 便捷的获取页面中动态加载的数据
  • requests模块进行数据爬取:可见非可得
  • selenium:可见即可得
  • 实现模拟登录实例化某一款浏览器对象(驱动程序的路径)
    • 基本操作:
    • 谷歌浏览器驱动程序下载地址:http://chromedriver.storage.googleapis.com/index.html
    • 驱动程序和谷歌版本的映射关系表:https://blog.csdn.net/huilan_same/article/details/51896672
  • find系列的函数用作于标签定位
  • 动作链:一系列的行为动作
  • 无头浏览器:无可视化界面的浏览器.
  • phantomJS

线程池

from multiprocessing.dummy import Pool
import requests
import time
#同步代码
# start = time.time()
# pool = Pool(3)
#
# urls = ['http://127.0.0.1:5000/bobo','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom']
# for url in urls:
# page_text = requests.get(url).text
# print(page_text)
# print('总耗时:',time.time()-start) #异步代码
start = time.time()
pool = Pool(3)
urls = ['http://127.0.0.1:5000/bobo','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom']
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)

协程对象

# -*- coding: utf-8 -*-
# __author__ = "maple" from time import sleep
import asyncio async def get_request(url):
print('正在请求:',url)
sleep(2)
print('请求结束:',url) c = get_request('www.1.com')
print(c)

任务对象

# -*- coding: utf-8 -*-
# __author__ = "maple" from time import sleep
import asyncio #回调函数:
#默认参数:任务对象
def callback(task):
print('i am callback!!1')
print(task.result())#result返回的就是任务对象对应的那个特殊函数的返回值 async def get_request(url):
print('正在请求:',url)
sleep(2)
print('请求结束:',url)
return 'hello bobo' #创建一个协程对象
c = get_request('www.1.com')
#封装一个任务对象
task = asyncio.ensure_future(c) #给任务对象绑定回调函数
task.add_done_callback(callback) #创建一个事件循环对象
loop = asyncio.get_event_loop()
loop.run_until_complete(task)#将任务对象注册到事件循环对象中并且开启了事件循环 多任务异步协程 import asyncio
from time import sleep
import time
start = time.time()
urls = [
'http://localhost:5000/index',
'http://localhost:5000/index',
'http://localhost:5000/index'
]
#在待执行的代码块中不可以出现不支持异步模块的代码
#在该函数内部如果有阻塞操作必须使用await关键字进行修饰
async def get_request(url):
print('正在请求:',url)
await asyncio.sleep(2)
print('请求结束:',url)
return 'hello bobo' tasks = [] #放置所有的任务对象
for url in urls:
c = get_request(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)

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

import asyncio
import requests
import time
start = time.time()
urls = [
'http://localhost:5000/index',
'http://localhost:5000/index',
'http://localhost:5000/index'
]
#无法实现异步的效果:是因为requests模块是一个不支持异步的模块
async def req(url):
page_text = 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)

aiohttp的使用

import asyncio
import requests
import time
import aiohttp
from lxml import etree
urls = [
'http://localhost:5000/index',
'http://localhost:5000/index',
'http://localhost:5000/index',
'http://localhost:5000/index',
'http://localhost:5000/index',
'http://localhost:5000/index',
]
#无法实现异步的效果:是因为requests模块是一个不支持异步的模块
async def req(url):
async with aiohttp.ClientSession() as s:
async with await s.get(url) as response:
#response.read():byte
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)
if __name__ == '__main__':
start = time.time()
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的演示程序

from selenium import webdriver
from time import sleep # 后面是你的浏览器驱动位置,记得前面加r'','r'是防止字符转义的
driver = webdriver.Chrome(r'C:\Users\oldboy-python\Desktop\爬虫+数据\day04\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的基本操作

from selenium import webdriver
from time import sleep
#实例化一个浏览器对象
bro = webdriver.Chrome(executable_path=r'C:\Users\oldboy-python\Desktop\爬虫+数据\day04\chromedriver.exe')
url = 'https://www.jd.com/'
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()

selenium爬取动态加载的数据

from selenium import webdriver
from lxml import etree
from time import sleep
#实例化一个浏览器对象
page_text_list = []
bro = webdriver.Chrome(executable_path=r'C:\Users\oldboy-python\Desktop\爬虫+数据\day04\chromedriver.exe')
url = 'http://125.35.6.84:81/xk/'
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(3)
bro.quit()

动作链

from lxml import etree
from time import sleep
from selenium import webdriver
from selenium.webdriver import ActionChains
#实例化一个浏览器对象
page_text_list = []
bro = webdriver.Chrome(executable_path=r'C:\Users\oldboy-python\Desktop\爬虫+数据\day04\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')
div_tag = bro.find_element_by_id('draggable') #1.实例化动作链对象
action = ActionChains(bro)
action.click_and_hold(div_tag) for i in range(5):
#让动作链立即执行
action.move_by_offset(17,0).perform()
sleep(0.5) action.release() sleep(3) bro.quit()

无头浏览器

from selenium.webdriver.chrome.options import Options
from time import sleep
from selenium import webdriver # 创建一个参数对象,用来控制chrome以无界面模式打开
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu') #实例化一个浏览器对象
bro = webdriver.Chrome(executable_path=r'C:\Users\oldboy-python\Desktop\爬虫+数据\day04\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规避风险

# -*- coding: utf-8 -*-
# __author__ = "maple" from time import sleep
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/')

12306模拟登陆

from selenium import webdriver
from selenium.webdriver import ActionChains
from PIL import Image #用作于图片的裁剪
from ChaoJiYing import Chaojiying_Client
from time import sleep
bro = webdriver.Chrome(executable_path=r'C:\Users\oldboy-python\Desktop\爬虫+数据\day04\chromedriver.exe')
bro.get('https://kyfw.12306.cn/otn/login/init')
sleep(5)
#验证码图片进行捕获(裁剪)
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()

超级鹰

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()

爬虫必知必会(4)_异步协程-selenium_模拟登陆的更多相关文章

  1. python网络爬虫,知识储备,简单爬虫的必知必会,【核心】

    知识储备,简单爬虫的必知必会,[核心] 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境,实验中会用到桌 ...

  2. 《MySQL必知必会》通配符 ( like , % , _ ,)

    <MySQL必知必会>通配符 ( like , % , _ ,) 关键字 LIke WHERE 搜索子句中使用通配符,必须使用 LIKE 操作符. % 百分号通配符 % 表示任意字符出现任 ...

  3. 读书笔记--SQL必知必会--建立练习环境

    书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL in 10 Minutes - Fourth Edition> MyS ...

  4. 《MySQL 必知必会》读书总结

    这是 <MySQL 必知必会> 的读书总结.也是自己整理的常用操作的参考手册. 使用 MySQL 连接到 MySQL shell>mysql -u root -p Enter pas ...

  5. 《SQL必知必会》学习笔记(一)

    这两天看了<SQL必知必会>第四版这本书,并照着书上做了不少实验,也对以前的概念有得新的认识,也发现以前自己有得地方理解错了.我采用的数据库是SQL Server2012.数据库中有一张比 ...

  6. SQL 必知必会

    本文介绍基本的 SQL 语句,包括查询.过滤.排序.分组.联结.视图.插入数据.创建操纵表等.入门系列,不足颇多,望诸君指点. 注意本文某些例子只能在特定的DBMS中实现(有的已标明,有的未标明),不 ...

  7. 0005 《SQL必知必会》笔记01-SELECT语句

    1.SELECT基本语句: SELECT 字段名1,···,字段名n FROM 表名 2.检索所有字段,用"*"替换字段名,这会导致效率低下 SELECT * FROM 表名; 3 ...

  8. 2015 前端[JS]工程师必知必会

    2015 前端[JS]工程师必知必会 本文摘自:http://zhuanlan.zhihu.com/FrontendMagazine/20002850 ,因为好东东西暂时没看懂,所以暂时保留下来,供以 ...

  9. [ 学习路线 ] 2015 前端(JS)工程师必知必会 (2)

    http://segmentfault.com/a/1190000002678515?utm_source=Weibo&utm_medium=shareLink&utm_campaig ...

随机推荐

  1. IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇)【转】

    同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别? 详细请看下链接: IO ...

  2. ARM汇编--汇编中符号和变量

    习惯了使用C语言的情况下我发现自己对与汇编程序的符号和变量的理解很不深刻,今天抽空来学学加深理解.以ARM汇编来说,在汇编代码中所有以"."开头的指令都是汇编伪指令,他们不属于AR ...

  3. Shell 编程快速上手

    Shell 编程快速上手 test.sh #!/bin/sh cd ~ mkdir shell_tut cd shell_tut for ((i=0; i<10; i++)); do touch ...

  4. npm version ^ meaning

    npm version ^ meaning ^ 更新版 https://docs.npmjs.com/cli/v6/commands/npm-version https://github.com/ge ...

  5. 正则表达式: javascript Unicode 中文字符 编码区间:\u4e00-\u9fa5

    正则表达式: javascript Unicode 中文字符  编码区间:\u4e00-\u9fa5 RegExp 对象 javascript Unicode 中文字符的 编码区间: \u4e00-\ ...

  6. Recoil & React official state management

    Recoil & React official state management Redux Recoil.js https://recoiljs.org/ A state managemen ...

  7. Jupyter All In One

    Jupyter All In One Jupyter Architecture https://jupyter.readthedocs.io/en/latest/projects/architectu ...

  8. input support upload excel only

    input support upload excel only demo https://codepen.io/xgqfrms/pen/vYONpLB <!-- <input placeh ...

  9. 「NGK每日快讯」2021.1.26日NGK公链第84期官方快讯!

  10. NGK Global英国路演落下帷幕,区块链赋能大数据取得新突破

    NGK全球巡回路演于7月25日在英国圆满举行,此次路演是由NGK英国社区主办,旨在探讨当前大数据爆炸的形式下,区块链如何赋能,解决行业痛点.会上,行业精英.区块链爱好者.各实体产业代表以及科技人员纷纷 ...