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

协程:对象.可以把协程当做是一个特殊的函数.如果一个函数的定义被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. Linux-用户/用户组身份提权

    sudo 身份提权(更安全) su命令在切换用户身份时,如果每个普通用户都能拿到root用户的密码,当其中某个用户不小心泄漏了root的密码,那系统会变得非常不安全. 为了改进这个问题,从而产生了su ...

  2. codeforces 10C Digital Root(非原创)

    Not long ago Billy came across such a problem, where there were given three natural numbers A, B and ...

  3. canvas实现简易时钟效果

    代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8& ...

  4. hdu5303贪心

    http://acm.hdu.edu.cn/showproblem.php?pid=5303 说一下题目大意.. 有一个长为L的环..你家在原点位置0,那么剩下L-1个点上种有一些树, 给你树的位置和 ...

  5. 017.NET5_内置容器基本使用

    IOC容器IServiceCollection .net 5已经内置了IOC容器. 什么是IOC? 把对象的创建交给第三方容器去创建 如何使用内置的 IOC IServiceCollection ? ...

  6. API 授权 All In One

    API 授权 All In One 身份验证 授权类型 身份验证类型 继承认证 没有认证 API密钥 不记名令牌 基本认证 摘要授权 OAuth 1.0 OAuth 2.0 授权码 隐含的 密码凭证 ...

  7. Express vs Koa

    Express vs Koa https://www.esparkinfo.com/express-vs-koa.html https://www.cleveroad.com/blog/the-bes ...

  8. linux move file / folder bash command

    linux move file / folder bash command mv $ which mv $ man mv # mv [-f] source target/ target folder ...

  9. taro taro 多端同步调试

    taro 多端同步调试 debug https://nervjs.github.io/taro/docs/envs-debug.html

  10. 【C#】反射的用法及效率对比

    反射实例化类 public class Person { public string Name { get; set; } public Person(string name) { this.Name ...