100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 爬虫之 单线程+多任务异步协程

爬虫之 单线程+多任务异步协程

时间:2018-11-10 12:14:26

相关推荐

爬虫之 单线程+多任务异步协程

单线程+多任务异步协程的概念

实现的意义: 提取爬取数据的效率实现异步爬虫的方式 多线程/多进程(不建议)池(适当)单线程+多任务异步协程(推荐)概念 协程:协程对象。可以使用async关键字修饰一个函数的定义(特殊的函数),当该特殊的函数被调用后,就可以返回一个协程对象。当函数调用后,函数内部的实现语句不会被立即执行 协程 == 特殊函数任务对象 本质上就是对协程对象的进一步封装 任务对象 == 特殊函数给任务对象绑定一个回调 add_done_callback(callback)事件循环(EventLoop):无限的循环对象 我们必须将任务对象注册到事件循环对象中,然后开启事件循环对象事件循环对象在执行任务对象的时候是基于异步await async注意事项 保证特殊函数内部不可以出现不支持异步模块对应的代码在特殊函数内部遇到阻塞操作必须使用await关键字对其进行手动挂起如果想要将多个任务对象注册到事件循环中,必须将多个任务对象封装到一个列表中,然后将列表注册(必须使用wait方法将列表中的任务对象进行挂起)到事件循环中aiohttp模块 是一个支持异步的网络请求模块pip install aiohttpselenium模块的使用 概念:就是一个基于浏览器自动化的模块elenium和爬虫之间的关联 很便捷的捕获动态加载的数据 - 可见即可得实现模拟登陆使用 环境的安装: pip install selenium下载一个浏览器的驱动程序谷歌驱动下载:http://chromedriver./index.html驱动程序和浏览器版本的映射关系:/huilan_same/article/details/51896672创建某一款一个浏览器对象动作链 如果想要触发一系列连续的行为动作

代码逻辑:

定义一个特殊的函数,协程对象

import asyncioimport time# 定义了一个特殊的函数# 特殊:调用后会返回一个协程对象,且函数内部的实现语句不会被立即执行# 创建一个协程对象async def test(num):print(num)c = test(10)print(c)

#<coroutine object test at 0x0000025058808A40>

封装一个任务对象

#封装一个任务对象async def test(num):print(num)c = test(10)# #根据协程对象封装了一个任务对象task = asyncio.ensure_future(c)print(task)

#<Task pending coro=<test() running at H:/autoclient/test/test.py:6>>

创建事件并执行

#事件循环对象async def request(url):print('正在请求:',url)time.sleep(2)print('请求完毕!',url)c1 = request('')task_A = asyncio.ensure_future(c1)#创建一个事件循环对象loop = asyncio.get_event_loop()#将任务对象注册到该对象中并且启动事件循环loop.run_until_complete(task_A)

任务对象的绑定回调

import asyncioimport timeasync def request(url):print('正在请求:',url)time.sleep(2)print('请求完毕!',url)return url#定义一个任务对象的回调函数#task参数表示的就是该函数被绑定的那个任务对象def task_callback(task):print('i am task_callback()')print(task.result())#task.result()返回的就是任务对象对应的特殊函数内部的返回值c = request('')task = asyncio.ensure_future(c)task.add_done_callback(task_callback)loop = asyncio.get_event_loop()loop.run_until_complete(task)

多任务异步协程:

import asyncioimport timestart = time.time()#在特殊函数内部不可以出现不支持异步模块相关的代码async def request(url):print('正在请求:',url)# time.sleep(2)#time模块是不支持异步await asyncio.sleep(2) #阻塞操作必须使用await关键字进行挂起print('请求完毕!',url)return urlurls = ['','','']def task_callback(task):print(task.result())tasks = [] #多任务列表:存放多个任务对象for url in urls:c = request(url)task = asyncio.ensure_future(c)task.add_done_callback(task_callback)tasks.append(task) #将多个任务对象装在到一个任务列表中loop = asyncio.get_event_loop()#多任务注册#wait就是将任务列表中的任务对象进行挂起loop.run_until_complete(asyncio.wait(tasks))print(time.time()-start)

多任务异步爬虫测试:一般开500个协程

flask代码:

from flask import Flaskimport timeapp = Flask(__name__)@app.route('/bobo')def index_bobo():time.sleep(2)return 'Hello bobo'@app.route('/jay')def index_jay():time.sleep(2)return 'Hello jay'@app.route('/tom')def index_tom():time.sleep(2)return 'Hello tom'if __name__ == '__main__':app.run(threaded=True)

爬虫测试代码:

import asyncioimport timeimport requestsstart = time.time()#在特殊函数内部不可以出现不支持异步模块相关的代码async def request(url):print('正在请求:',url)response = requests.get(url)return response.texturls = ['http://127.0.0.1:5000/bobo','http://127.0.0.1:5000/tom','http://127.0.0.1:5000/jay']def parse(task):page_text = task.result()print(page_text+',请求到的数据!!!')tasks = []for url in urls:c = request(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)

aiohttp的使用:

mport asyncioimport timeimport aiohttpstart = time.time()#在特殊函数内部不可以出现不支持异步模块相关的代码#简单的基本架构:# async def request(url):# with aiohttp.ClientSession() as s:# #s.get/post和requests中的get/post用法几乎一样:url,headers,data/prames# #在s.get中如果使用代理操作:proxy="http://ip:port"# with s.get(url) as response:# #获取字符串形式的响应数据:response.text()# #获取byte类型的:response.read()# page_text = response.text()# return page_text#在当前架构的基础上补充细节即可#细节1:在每一个with前加上async关键字#细节2:在get方法前和response.text()前加上await关键字进行手动挂起操作async def request(url):async with aiohttp.ClientSession() as s:#s.get/post和requests中的get/post用法几乎一样:url,headers,data/prames#在s.get中如果使用代理操作:proxy="http://ip:port" async with await s.get(url) as response:#获取字符串形式的响应数据:response.text()#获取byte类型的:response.read()page_text = await response.text()return page_text# urls = [#'http://127.0.0.1:5000/bobo',#'http://127.0.0.1:5000/tom',#'http://127.0.0.1:5000/jay',#'http://127.0.0.1:5000/bobo',#'http://127.0.0.1:5000/tom',#'http://127.0.0.1:5000/jay',#'http://127.0.0.1:5000/bobo',#'http://127.0.0.1:5000/tom',#'http://127.0.0.1:5000/jay',# ]urls = []for i in range(500):urls.append('http://127.0.0.1:5000/bobo')def parse(task):page_text = task.result()print(page_text+',请求到的数据!!!')tasks = []for url in urls:c = request(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)

案例:

import aiohttpimport asynciofrom lxml import etreeall_titles = []headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'}async def request(url):async with aiohttp.ClientSession() as s:async with await s.get(url,headers=headers) as response:page_text = await response.text()return page_texturls = []url = '/index.php/question/questionType?type=4&page=%d'for page in range(100):u_page = page * 30new_url = format(url%u_page)urls.append(new_url)tasks = []def parse(task):page_text = task.result()page_text = page_text.encode('gb2312').decode('gbk')tree = etree.HTML(page_text)tr_list = tree.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr')for tr in tr_list:title = tr.xpath('./td[2]/a[2]/text()')[0]print(title)all_titles.append(title)for url in urls:c = request(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))

selenim演示:

from selenium import webdriverfrom time import sleep# 后面是你的浏览器驱动位置,记得前面加r'','r'是防止字符转义的driver = webdriver.Chrome(r'chromedriver.exe')# 用get打开百度页面driver.get("")# 查找页面的“设置”选项,并进行点击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 webdriverfrom time import sleep

//chromedriver.exe 浏览器的驱动文件bro = webdriver.Chrome(executable_path='chromedriver.exe')#发起指定url的请求bro.get('/')#在搜索框中搜索商品#可以使用find系列的方法进行标签定位search_input = bro.find_element_by_xpath('//*[@id="key"]')#想搜索框中写入商品名称search_input.send_keys('iphonex')sleep(2)btn = bro.find_element_by_xpath('//*[@id="search"]/div/div[2]/button')btn.click()sleep(2)#执行js让滚轮向下滑动,滑动一屏bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')sleep(2)# bro.execute_script('window.scrollTo(0,-document.body.scrollHeight)')page_text = bro.page_sourcewith open('./jingdong.html','w',encoding='utf-8') as fp:fp.write(page_text)print(page_text)sleep(4)#关闭浏览器bro.quit()

selenium的动作链

from selenium import webdriverfrom selenium.webdriver import ActionChains #动作连from time import sleepbro = webdriver.Chrome(executable_path='chromedriver.exe')bro.get('/try/try.php?filename=jqueryui-api-droppable')#定位要拖动的标签#定位的标签是存在于iframe的子页面中,如果直接使用find做定位,是定位不到的# target_ele = bro.find_element_by_id('draggable')#像定位iframe中子页面中的标签必须进行如下操作bro.switch_to.frame('iframeResult')target_ele = bro.find_element_by_id('draggable')#基于动作连实现滑动操作action = ActionChains(bro)#点击且长按action.click_and_hold(target_ele)for i in range(5):#perform()表示立即执行动作连指定好的动作action.move_by_offset(17,0).perform()sleep(0.5)action.release()sleep(4)bro.quit()

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。