selenium_0">线程池&多任务异步协程&selenium
异步爬虫
特点:应付面试
- 基于线程池
- 基于单线程+多任务的异步爬虫
线程池
python">import requests
import time
#****************************************
#线程池库
form multiprocessing.dumpy import Pool
#****************************************
def get_request(url):
page_text = requests.get(url=url).text
return len(page_text)
#同步代码
if __name__ == "__main__":
start = time.time()
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:
res = get_request(url)
print(res)
print('总耗时:',time.time-start)
#2*3 = 6秒多一点
#异步代码
if __name__ == "__main__":
start = time.time()
#****************************************
pool = Pool(3) #3表示开启线程的数量
#func是回调函数,alist是可迭代类型对象(列表)。这里表示基于线程池的3个线程,需要回调依次对列表中的每一个列表元素进行异步操作,假设列表有3个列表元素,那么回调就会调3次,对3个列表元素,基于3个线程,进行异步操作
#pool.map(func,alist)
#使用get_request作为回调函数,需要基于异步的形式对urls列表中的每一个列表元素进行操作
#保证回调函数必须要有1个参数和有返回值
result_list = pool.map(get_request,urls)
#****************************************
print(result_list)
print('总耗时:',time.time-start)
#2秒多一点
单线程+多任务异步协程
基本概念2️⃣3️⃣
pip install asyncio
- 特殊的函数
- 如果一个函数的定义被async修饰后,则该函数就变成了一个特殊的函数
- 特殊之处:
- 该特殊的函数调用后,函数内部的实现语句不会被立即执行
- 该特殊函数被调用后会返回一个协程对象
- 协程对象
- 对象。通过特殊函数的调用返回一个协程对象。
- 协程 == 特殊函数 == 一组指定的操作
- 协程 == 一组指定的操作
python">async def get_request(url):
xxx
#c就是一个协程对象
c = get_request('www.1.com')
-
任务对象
-
任务对象就是一个高级的协程对象(任务对象就是对协程对象的进一步封装)
-
任务对象 == 协程对象 == 特殊函数 == 一组指定操作
-
任务对象 == 一组指定操作
-
创建任务对象:
python">#任务对象就是对协程对象的进一步封装 task = asyncio.ensure_future(c)
-
任务对象的高级之处
-
可以给任务对象绑定回调:
python">async def get_request(url): xxx return 'bobo' #回调函数的封装 #参数t:就是该回调函数的调用者(任务对象) def task_callback(t): print('i am task callback(),参数t:',t) #result返回的就是特殊函数的返回值 print('t.result()返回的是:',t.result()) #给task绑定一个回调函数 task.add_done_callback(task_callback)
-
回调函数的调用时机:
任务被执行完结束后,才可以调用回调函数
-
回调函数的参数只可以有一个:表示的就是该回调函数的调用者(任务对象)
-
-
-
使用回调函数的参数调用result()返回的就是任务对象表示的特殊函数return的结果
-
-
事件循环对象
-
作用:
- 可以将多个任务对象注册/装载到事件循环对象中
- 如果开启了事件循环后,则其内部注册/装载的任务对象表示的指定操作就会被基于异步的被执行
-
创建方式,注册且启动方式
python">#创建事件循环对象 loop = asyncio.get_event_loop() #将任务对象注册到事件循环中且开启事件循环 loop.run_until_complete(task) #无法使用
-
python">#必须使用wait方法对tasks进行封装才可
loop.run_until_complete(asyncio.wait(tasks))
-
依然6秒的解释(手记,详细)
每一个任务对象都表示一组指定的操作
指定的操作中:可能会存在阻塞操作(比如sleep,get,post)
事件循环对象(loop)在最开始的时候是基于按照顺序对每一个任务对象进行执行
当loop在执行某一个任务对象时,遇到了阻塞操作,则loop会跳过阻塞操作执行下一个任务对象。
当loop在执行到某一个任务对象的时候,前面的一个任务对象的阻塞操作结束了,loop会回头将该阻塞结束后的任务对象阻塞之后的操作进行执行。
wait(tasks)作用:可以将任务列表中的任务对象进行可挂起操作。(每一个任务对象都是可以被挂起)
任务对象的挂起:将当前挂起的任务对象交出CPU的使用权。只有当任务对象的CPU的使用权交出后,loop才可以使用CPU去执行下一个任务对象。
-
wait方法的作用(精要)
将任务列表中的任务对象赋予可被挂起的权限。只有任务对象被赋予了可被挂起的权限后,该任务对象才可以被挂起
- 挂起:将当前的任务对象交出CPU的使用权
-
注意事项【重要】
在特殊函数内部不可以出现不支持异步模块对应的代码,否则会中断整个异步效果
-
await关键字
在特殊函数内部,凡是阻塞参数前都必须使用await进行修饰。await就可以保证阻塞操作在异步执行的过程中不会被跳过。
python">async def get_request(url):
print('正在请求的url:',url)
await asyncio.sleep(2) #支持异步模块的代码
print('请求结束',url)
return 'bobo'
多任务的异步爬虫4️⃣
aiohttp
- 是一个支持异步的网络请求模块
- pip install aiohttp
使用代码
- 写出一个大致的架构
- 补充细节
- 在阻塞操作前加上await关键字
- 在每一个with前加上async关键字
python">async def get_request(url):
#实例化好了一个请求对象
async with aiohttp.ClientSession() as sess:
#调用get发起请求,返回一个响应对象
#get/post(url,headers,params/data,proxy="http://ip:port")
async with await sess.get(url=url) as response:
#text()获取了字符串形式的响应数据
#read()获取byte类型的响应数据
page_text = await response.text()
return page_text
多任务爬虫的数据解析
- 一定要使用任务对象的回调函数实现数据解析
- why
- 多任务的架构中数据的爬取是封装在特殊函数中,我们一定要保证数据请求结束后,再实现数据解析
使用多任务的异步协程爬取数据实现套路
- 可以先使用requests模块将待请求数据对应的url封装到一个列表中(同步)
- 可以使用aiohttp模式将列表中的url进行异步的请求和数据解析(异步)
selenium_221">selenium
概念
-
基于浏览器自动化的模块
-
自动化:可以通过代码指定一系列的行为动作,然后将其作用到浏览器中
-
pip install selenium
selenium_230">selenium和爬虫之间的关联
- 可以便捷的捕获到任意形式动态加载的数据(可见即可得)
- 实现模拟登录
谷歌驱动下载地址:http://chromedriver.storage.googleapis.com/index.html
简单的使用方法1️⃣
如何捕获动态加载的数据2️⃣
- 药监总局为例
- 将前三页所有企业名称爬取
弊端
- 效率低
动作链ActionChains3️⃣
定义:一系列连续的动作(滑动动作)
selenium_252">让selenium规避监测
实现步骤:
-
必须将你电脑中安装的谷歌浏览器的驱动程序所在的目录找到。且将目录添加到环境变量中。
-
打开cmd,在命令行中输入指令
chrome.exe --remote-debugging-port=9222 --user-data-dir=“一个空文件夹的目录”
指令执行结束后,会打开你本机安装好的谷歌浏览器
-
执行如下代码:可以使用下属代码接管步骤2打开真实的浏览器
python">from selenium import webdriver from selenium.webdriver.chrome.options import options chrome_options = Options() chrome_options.add_experimental_option("debuggerAddress","127.0.0.1:9222") #本机安装好谷歌的驱动程序路径 chrome_driver = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" driver = webdriver.Chrome(executable_path=chrome_driver,chrome_options=chrome_options) print(driver.title)
无头浏览器(无可视化界面的浏览器)
除了不显示界面,和可视化的selenium没有任何区别
-
谷歌无头浏览器(推荐)
python">from selenuim import webdriver from selenuim.webdriver.chrome.options import Options import time #创建一个参数对象,用来控制chrome以无界面模式打开 chrome_options = Options() chrome_options.add_argument('--headless') chrome_options.add_argument('--disable-gpu') #驱动路径,自己改 path = './chromedriver.exe' #创建浏览器对象 browser = webdriver.Chrome(executable_path=path,chrome_options=chrome_options) #上网 url = 'http://www.baidu.com/' browser.get(url) time.sleep(3) #截图 browser.save_screenshot('baidu.png') print(browser.page_source) browser.quit()
-
phantomJs