爬虫手册05 异步爬虫

2023-11-04

异步爬虫

目标:例举asyncioaiohttp模块的常规用法代码

关于协程概念参考:https://blog.csdn.net/weixin_40743639/article/details/122394616?spm=1001.2014.3001.5502

一. 协程的基本原理

1. 定义协程

方式一:
import asyncio

async def execute(x):	# 定义协程函数
    print('Number:', x)

coroutine = execute(1)	# 调用协程函数返回协程对象
print('Coroutine:', coroutine)	# 打印协程对象
print('After calling execute')

loop = asyncio.get_event_loop()	# 获取事件循环
loop.run_until_complete(coroutine)	# 将协程添加到事件循环,并启动
print('After calling loop')
运行效果:
Coroutine: <coroutine object execute at 0x00000225FF3263C8>
After calling execute
Number: 1
After calling loop
方式二:

将协程对象打包成任务对象,操作有点多余。

import asyncio

async def execute(x):	# 定义协程函数
    print('Number:', x)
    return x

coroutine = execute(1)	# 调用协程函数返回协程对象
print('Coroutine', coroutine)	# 打印协程对象
print('After calling execute')

loop = asyncio.get_event_loop()	# 获取事件循环
task = loop.create_task(coroutine)	# 将协程对象打包成任务对象
print('Task:', task)	# 打印任务对象,挂起状态
loop.run_until_complete(task)	# 将任务添加到事件循环,并启动
print('Task:', task)	# 打印任务对象,完成状态
print('After calling loop')
运行效果:
Coroutine <coroutine object execute at 0x0000022DE4DE54C8>
After calling execute
Task: <Task pending coro=<execute() running at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/03_demo3.py:3>>
Number: 1
Task: <Task finished coro=<execute() done, defined at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/03_demo3.py:3> result=1>
After calling loop
方式三:

如果要添加回调函数,使用这种方法

import asyncio

async def execute(x):	# 定义协程函数
    print('Number:', x)
    return x

coroutine = execute(1)	# 调用协程函数返回协程对象
print('Coroutine:', coroutine)	# 打印协程对象
print('After calling execute')

task = asyncio.ensure_future(coroutine)	# 确保协程对象是一个future对象,和task对象一样
print('Task:', task)	# 打印任务对象,挂起状态
loop = asyncio.get_event_loop()	# 获取事件循环
loop.run_until_complete(task)	# 将任务添加到事件循环,并启动
print('Task:', task)	# 打印任务对象,完成状态
print('After calling loop')
运行效果:
Coroutine: <coroutine object execute at 0x00000225050154C8>
After calling execute
Task: <Task pending coro=<execute() running at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/04_demo4.py:3>>
Number: 1
Task: <Task finished coro=<execute() done, defined at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/04_demo4.py:3> result=1>
After calling loop

2. 绑定回调

import asyncio
import requests

async def request():	# 定义协程函数
    url = 'https://www.baidu.com'
    status = requests.get(url)
    return status

def callback(task):		# 定义回调函数
    print('Status:', task.result())

coroutine = request()	# 调用协程函数返回协程对象
task = asyncio.ensure_future(coroutine)	# 确保协程对象是一个future对象,和task对象一样
task.add_done_callback(callback)	# 给任务添加回调函数
print('Task:', task)	# 打印任务对象,挂起状态

loop = asyncio.get_event_loop()		# 获取事件循环
loop.run_until_complete(task)	# 将任务添加到事件循环,并启动
print('Task:', task)	# 打印任务对象,完成状态
运行效果:
Task: <Task pending coro=<request() running at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/05_demo5.py:4> cb=[callback() at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/05_demo5.py:9]>
Status: <Response [200]>
Task: <Task finished coro=<request() done, defined at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/05_demo5.py:4> result=<Response [200]>>

也可以不通过回调函数获得协程任务的执行结果

import asyncio
import requests

async def request():	# 定义协程函数
    url = 'https://www.baidu.com'
    status = requests.get(url)
    return status

coroutine = request()	# 调用协程函数返回协程对象
task = asyncio.ensure_future(coroutine)	# 确保协程对象是一个future对象,和task对象一样
print('Task:', task)	# 打印任务对象,挂起状态

loop = asyncio.get_event_loop()		# 获取事件循环
loop.run_until_complete(task)		# 将任务添加到事件循环,并启动
print('Task:', task)	# 打印任务对象,完成状态
print('Task Result:', task.result())	# 打印协程函数的返回值
运行效果:
Task: <Task pending coro=<request() running at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/06_demo6.py:4>>
Task: <Task finished coro=<request() done, defined at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/06_demo6.py:4> result=<Response [200]>>
Task Result: <Response [200]>

3. 多任务协程

import asyncio
import requests

async def request():	# 定义协程函数
    url = 'https://www.baidu.com'
    status = requests.get(url)
    return status

tasks = [asyncio.ensure_future(request()) for _ in range(5)]	# 利用列表生成式,调用协程函数返回协程对象列表
print('Tasks:', tasks)	# 打印协程任务列表

loop = asyncio.get_event_loop()		# 获取事件循环
loop.run_until_complete(asyncio.wait(tasks))	# 将任务列表添加到事件循环,并启动

for task in tasks:
    print('Task Result:', task.result())	# 打印协程函数的返回值
运行效果:
Tasks: [<Task pending coro=<request() running at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/07_demo7.py:4>>, <Task pending coro=<request() running at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步
爬虫/6.1 协程的基本原理/AsyncTest/07_demo7.py:4>>, <Task pending coro=<request() running at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/07_demo7.py:4>>, <Task pending coro=<request() running at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/07_demo7.py:4>>, <Task pending coro=<request() running at c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/07_demo7.py:4>>]    
Task Result: <Response [200]>
Task Result: <Response [200]>
Task Result: <Response [200]>
Task Result: <Response [200]>
Task Result: <Response [200]>

4. 使用aiohttp

import asyncio
import aiohttp
import time

start = time.time()

async def get(url):		# 定义协程函数
    session = aiohttp.ClientSession()
    response = await session.get(url)	# 原本需要阻塞等待的地方前面加上await,切换到其他协程任务
    await response.text()	# 协程开启后,只要返回的是协程对象就需要在前面加上await
    await session.close()
    return response

async def request():
    url = 'https://httpbin.org/delay/5'
    print('Waiting for', url)
    response = await get(url)	# 协程开启后,只要返回的是协程对象就需要在前面加上await
    print('Get response from', url, 'response', response)

tasks = [asyncio.ensure_future(request()) for _ in range(3)]	# 利用列表生成式,调用协程函数返回协程对象列表
loop = asyncio.get_event_loop()		# 获取事件循环
loop.run_until_complete(asyncio.wait(tasks))	# 将任务列表添加到事件循环,并启动

end = time.time()
print('Cost time:', end - start)
运行效果:
Waiting for https://httpbin.org/delay/5
Waiting for https://httpbin.org/delay/5
Waiting for https://httpbin.org/delay/5
Get response from https://httpbin.org/delay/5 response <ClientResponse(https://httpbin.org/delay/5) [200 OK]>
<CIMultiDictProxy('Date': 'Wed, 16 Mar 2022 13:16:38 GMT', 'Content-Type': 'application/json', 'Content-Length': '360', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>

Get response from https://httpbin.org/delay/5 response <ClientResponse(https://httpbin.org/delay/5) [200 OK]>
<CIMultiDictProxy('Date': 'Wed, 16 Mar 2022 13:16:38 GMT', 'Content-Type': 'application/json', 'Content-Length': '360', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>

Get response from https://httpbin.org/delay/5 response <ClientResponse(https://httpbin.org/delay/5) [200 OK]>
<CIMultiDictProxy('Date': 'Wed, 16 Mar 2022 13:16:39 GMT', 'Content-Type': 'application/json', 'Content-Length': '360', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>

Cost time: 9.281606435775757

测试以下aiohttp多个协程访问百度的速度

import asyncio
import aiohttp
import time

def test(number):
    start = time.time()

    async def get(url):		# 定义协程函数
        session = aiohttp.ClientSession()
        response = await session.get(url)	# 原本需要阻塞等待的地方前面加上await,切换到其他协程任务
        await response.text()	# 协程开启后,只要返回的是协程对象就需要在前面加上await
        await session.close()	
        return response
    
    async def request():	# 定义协程函数
        url = 'https://www.baidu.com/'
        await get(url)		# 协程开启后,只要返回的是协程对象就需要在前面加上await
    
    tasks = [asyncio.ensure_future(request()) for _ in range(number)]	# 利用列表生成式,调用协程函数返回协程对象列表
    loop = asyncio.get_event_loop()		# 获取事件循环
    loop.run_until_complete(asyncio.wait(tasks))	# 将任务列表添加到事件循环,并启动

    end = time.time()
    print('Number:', number, 'Cost time:', end - start)

for number in [1, 3, 5, 10, 15, 30, 75, 100, 200, 500]:
    test(number)
运行效果:
Number: 1 Cost time: 0.12730693817138672
Number: 3 Cost time: 0.09128069877624512
Number: 5 Cost time: 0.08041119575500488
Number: 10 Cost time: 0.15501713752746582
Number: 15 Cost time: 0.1743018627166748
Number: 30 Cost time: 0.25256872177124023
Number: 75 Cost time: 0.7528872489929199
Number: 100 Cost time: 0.36460232734680176
Number: 200 Cost time: 0.9137499332427979
Number: 500 Cost time: 3.35489559173584

二. aiohttp的使用

1. 基本实例

import aiohttp
import asyncio

async def fetch(session, url):		# 定义协程函数
    async with session.get(url) as response:	# 协程函数中上下文管理器的写法
        return await response.text(), response.status

async def main():		# 定义协程函数
    async with aiohttp.ClientSession() as session:	# 协程函数中上下文管理器的写法
        html, status = await fetch(session, 'https://www.baidu.com/')	# 协程开启后,只要返回的是协程对象就需要在前面加上await
        print(f'html: {html[:100]}...')
        print(f'status: {status}')

if __name__ == '__main__':
    # asyncio.run(main())		# python3.7之后的写法,等价于下面两句话
    loop = asyncio.get_event_loop()		# 获取事件循环
    loop.run_until_complete(main())		# 将协程对象添加到事件循环,并启动
运行效果:
html: <html>
<head>
        <script>
                location.replace(location.href.replace("https://","http://"));
        </scri...
status: 200

2. URL参数设置

import aiohttp
import asyncio

async def main():	# 定义协程函数
    params = {'name': 'apphao', 'age': 25}
    async with aiohttp.ClientSession() as session:
        async with session.get('https://httpbin.org/get', params=params) as response:	# get请求,并携带参数
            print(await response.text())

if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())		# 获取事件循环,将协程对象添加到事件循环,并启动
运行效果:
{
  "args": {
    "age": "25",    
    "name": "apphao"
  },
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "Host": "httpbin.org",
    "User-Agent": "Python/3.7 aiohttp/3.8.1",
    "X-Amzn-Trace-Id": "Root=1-6231e602-74a6d4d74b9a70c761705a6c"
  },
  "origin": "218.82.172.215",
  "url": "https://httpbin.org/get?name=apphao&age=25"
}

3. POST请求

提交form表单
import aiohttp
import asyncio

async def main():	# 定义协程函数
    data = {'name': 'apphao', 'age': 25}
    async with aiohttp.ClientSession() as session:
        async with session.post('https://httpbin.org/post', data=data) as response:	# post请求,并携带参数
            print(await response.text())

if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())		# 获取事件循环,将协程对象添加到事件循环,并启动
运行效果:
{
  "args": {},
  "data": "",
  "files": {},
  "form": {
    "age": "25",
    "name": "apphao"
  },
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "Content-Length": "18",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "httpbin.org",
    "User-Agent": "Python/3.7 aiohttp/3.8.1",
    "X-Amzn-Trace-Id": "Root=1-6231e65a-1521583f3b18bb4d0b95dc45"
  },
  "json": null,
  "origin": "218.82.172.215",
  "url": "https://httpbin.org/post"
}
提交json字符串
import aiohttp
import asyncio

async def main():	# 定义协程函数
    data = {'name': 'apphao', 'age': 25}
    async with aiohttp.ClientSession() as session:
        async with session.post('https://httpbin.org/post', json=data) as response:	# post请求,并携带参数
            print(await response.text())

if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())		# 获取事件循环,将协程对象添加到事件循环,并启动
运行效果:
{
  "args": {},
  "data": "{\"name\": \"apphao\", \"age\": 25}",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "Content-Length": "29",
    "Content-Type": "application/json",
    "Host": "httpbin.org",
    "User-Agent": "Python/3.7 aiohttp/3.8.1",
    "X-Amzn-Trace-Id": "Root=1-6231e7f4-74d9b029347afc9f20a21534"
  },
  "json": {
    "age": 25,
    "name": "apphao"
  },
  "origin": "218.82.172.215",
  "url": "https://httpbin.org/post"
}

4. 响应

import aiohttp
import asyncio

async def main():
    data = {'name': 'apphao', 'age': 25}
    async with aiohttp.ClientSession() as session:
        async with session.post('http://www.httpbin.org/post', data=data) as response:
            print('status:', response.status)
            print('headers:', response.headers)
            print('body:', await response.text())	# 协程开启后,只要返回的是协程对象就需要在前面加上await
            print('bytes:', await response.read())	# 协程开启后,只要返回的是协程对象就需要在前面加上await
            print('json:', await response.json())	# 协程开启后,只要返回的是协程对象就需要在前面加上await

if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())
运行效果:
status: 200
headers: <CIMultiDictProxy('Date': 'Wed, 16 Mar 2022 13:41:52 GMT', 'Content-Type': 'application/json', 'Content-Length': '510', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
body: {
  "args": {},
  "data": "",
  "files": {},
  "form": {
    "age": "25",
    "name": "apphao"
  },
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "Content-Length": "18",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "www.httpbin.org",
    "User-Agent": "Python/3.7 aiohttp/3.8.1",
    "X-Amzn-Trace-Id": "Root=1-6231e920-42d270f01ad9475f4392ca31"
  },
  "json": null,
  "origin": "218.82.172.215",
  "url": "http://www.httpbin.org/post"
}

bytes: b'{\n  "args": {}, \n  "data": "", \n  "files": {}, \n  "form": {\n    "age": "25", \n    "name": "apphao"\n  }, \n  "headers": {\n    "Accept": "*/*", \n    "Accept-Encoding": "gzip, deflate", \n    "Content-Length": "18", \n    "Content-Type": "application/x-www-form-urlencoded", \n    "Host": "www.httpbin.org", \n    "User-Agent": "Python/3.7 aiohttp/3.8.1", \n    "X-Amzn-Trace-Id": "Root=1-6231e920-42d270f01ad9475f4392ca31"\n  }, \n  "json": null, \n  "origin": "218.82.172.215", \n  "url": "http://www.httpbin.org/post"\n}\n'
json: {'args': {}, 'data': '', 'files': {}, 'form': {'age': '25', 'name': 'apphao'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Content-Length': '18', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'www.httpbin.org', 'User-Agent': 'Python/3.7 aiohttp/3.8.1', 'X-Amzn-Trace-Id': 'Root=1-6231e920-42d270f01ad9475f4392ca31'}, 'json': None, 'origin': '218.82.172.215', 'url': 'http://www.httpbin.org/post'}

5. 超时设置

import aiohttp
import asyncio

async def main():
    timeout = aiohttp.ClientTimeout(total=1)
    async with aiohttp.ClientSession(timeout=timeout) as session:
        async with session.get('https://www.httpbin.org/get') as response:
            print('status:', response.status)

if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())
运行效果:
Traceback (most recent call last):
  File "c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/21_demo20.py", line 11, in <module>
    asyncio.get_event_loop().run_until_complete(main())
  File "C:\Users\Apphao\anaconda3\lib\asyncio\base_events.py", line 583, in run_until_complete
    return future.result()
  File "c:/Users/Apphao/Desktop/Python/cuiqingcai/6 异步爬虫/6.1 协程的基本原理/AsyncTest/21_demo20.py", line 7, in main
    async with session.get('https://www.httpbin.org/get') as response:
  File "C:\Users\Apphao\anaconda3\lib\site-packages\aiohttp\client.py", line 1138, in __aenter__
    self._resp = await self._coro
  File "C:\Users\Apphao\anaconda3\lib\site-packages\aiohttp\client.py", line 634, in _request
    break
  File "C:\Users\Apphao\anaconda3\lib\site-packages\aiohttp\helpers.py", line 721, in __exit__
    raise asyncio.TimeoutError from None
concurrent.futures._base.TimeoutError

6. 并发限制

import asyncio
import aiohttp

CONCURRENCY = 5		# 最大并发量为5
URL = 'https://www.baidu.com'

semaphore = asyncio.Semaphore(CONCURRENCY)	# 设置信号量为5
session = None

async def scrape_api():
    async with semaphore:	# 利用信号量来控制并发数
        print('scraping', URL)
        async with session.get(URL) as response:
            await asyncio.sleep(1)
            return await response.text()

async def main():
    global session
    session = aiohttp.ClientSession()
    scrape_index_tasks = [asyncio.ensure_future(scrape_api()) for _ in range(20)]
    await asyncio.gather(*scrape_index_tasks)

if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())

三. aiohttp异步爬取实战

import asyncio
import aiohttp
import logging
import json
from motor.motor_asyncio import AsyncIOMotorClient
import re
import time
from numpy import *

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s - %(levelname)s: %(message)s')

INDEX_URL = 'https://spa5.scrape.center/api/book/?limit=18&offset={offset}'     # 索引列表url
DETAIL_URL = 'https://spa5.scrape.center/api/book/{id}'                         # 详情信息url
PAGE_SIZE = 18      # 每一页的详情信息数量
PAGE_NUMBER = 100   # 页数
CONCURRENCY = 5     # 并发数5
MONGO_CONNECTION_STRING = 'mongodb://localhost:27017'   # mongodb数据库地址
MONGO_DB_NAME = 'books'                                 # 数据库名字
MONGO_COLLECTION_NAME = 'books2'                        # 档案名字

# 连接mongodb数据库
client = AsyncIOMotorClient(MONGO_CONNECTION_STRING)
db = client[MONGO_DB_NAME]
collection = db[MONGO_COLLECTION_NAME]

# 设置并发信号量
semaphore = asyncio.Semaphore(CONCURRENCY)
session = None

async def scrape_api(url):	# 用aiohttp访问url并返回json数据
    async with semaphore:
        for c in range(10):	# 重试机制10次
            try:
                logging.info('scraping %s', url)
                async with session.get(url) as response:
                    return await response.json()
            except aiohttp.ClientError:
                logging.error('error occurred while scraping %s', url, exc_info=True)

# 获取列表页
async def scrape_index(page):
    url = INDEX_URL.format(offset=PAGE_SIZE * (page - 1))   # 拼接索引页url
    return await scrape_api(url)        # 返回索引页url返回的json数据

# 字符串种多个空格变成一个空格
def spaceReplace(s):
    return re.sub(' +', ' ', s)

# 解析详情信息
def parse_detail(data):
    result = {}
    result['id'] = data.get('id')
    result['name'] = data.get('name')
    result['authors'] = spaceReplace(' '.join(data.get('authors')).strip())
    result['score'] = data.get('score')
    result['cover'] = data.get('cover')
    return result

# 获取详情信息
async def scrape_detail(id):
    url = DETAIL_URL.format(id=id)  # 拼接详情页url
    data = await scrape_api(url)    # 访问详情页
    result = parse_detail(data)     # 解析返回的json数据
    await save_data(result)         # 插入数据库

# 数据插入mongodb
async def save_data(data):	
    collection.update_one({
        'id': data.get('id')
    }, {
        '$set': data
    }, upsert=True)
    logging.info('save data success: %s', data.get('name'))

# 主函数
async def main():
    global session
    session = aiohttp.ClientSession()

    # 先用协程获取详情页url的id列表
    scrape_index_tasks = [asyncio.ensure_future(scrape_index(page)) for page in range(1, PAGE_NUMBER + 1)]
    results = await asyncio.gather(*scrape_index_tasks)
    ids = []
    for index_data in results:
        if not index_data: continue
        for item in index_data.get('results'):
            ids.append(item.get('id'))

    # 再用协程访问详情页url
    scrape_detail_tasks = [asyncio.ensure_future(scrape_detail(id)) for id in ids]
    await asyncio.wait(scrape_detail_tasks)
    await session.close()

if __name__ == '__main__':
    start = time.time()
    asyncio.get_event_loop().run_until_complete(main())
    end = time.time()
    logging.info('Cost time is %s', end - start)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

爬虫手册05 异步爬虫 的相关文章

随机推荐

  • 多台电脑环境下Python统一相同的库及对应版本

    工作时很容易遇到这种情况 就是公司电脑和个人电脑Python中对应的库的版本甚至种类不同 这样就可能导致用个人电脑编写的代码在公司电脑上跑不了 或者别的什么原因需要统一版本库 可以通过以下方式解决 当然有别的方式 例如Docker 首先 在
  • CentOS 7 开放3306端口(实现MySQL远程登陆)

    一 开放3306端口 1 开启端口3306 firewall cmd zone public add port 3306 tcp permanent 2 重启防火墙 firewall cmd reload 3 查看已经开放的端口 firew
  • ajax的使用 json格式传参

    json格式被认为进行ajax前后端交互比较方便 这里就贴上前端js的相关代码 首先绑定一个按钮 被点击时触发ajax方法 sendEmail btn on click function ajax type post 请求类型为post 关
  • 微服务项目nginx前后台配置实例

    微服务项目nginx配置实例 1 准备好nginx服务我本地版本是nginx 1 18 0 zip 2 将前台代码放入nginx html目录下 3 将修改config nginx conf文件 user nobody worker pro
  • ubuntu问题g++ : 依赖: g++-4.8 (>= 4.8.2-5~) 但是它将不会被安装

    截图中选取了一个等同的例子 python dev 依赖 libpython dev 2 7 5 5ubuntu3 但是它将不会被安装 凡是遇到类似问题 括号里面会是一些版本号 这通常代表的意思是Ubuntu自生安装的软件包版本高 而所安装软
  • [非线性控制理论]4_反馈线性化_反步法

    非线性控制理论 1 Lyapunov直接方法 非线性控制理论 2 不变性原理 非线性控制理论 3 基础反馈稳定控制器设计 非线性控制理论 4 反馈线性化 反步法 非线性控制理论 5 自适应控制器 Adaptive controller 非线
  • C语言编译器

    C语言编译器是指用于将C语言源代码转换成可执行程序的工具软件 编译器将C语言源程序转化为目标代码的过程称为编译 目标代码通常是机器码 可由计算机直接执行 常见的C语言编译器有 GCC GNU Compiler Collection GNU编
  • 【C++入门】文件流(fstream)介绍和使用

    1 打开函数 open mode 含义 ios in 以读取方式打开文件 ios out 以写入方式打开文件 ios binary 以二进制方式存取 ios ate 存取指针在文件末尾 ios app 写入时采用追加方式 ios trunc
  • 一个 SPI 转串口驱动的优化

    rel File List href file C 5CDOCUME 7E1 5Czjujoe 5CLOCALS 7E1 5CTemp 5Cmsohtml1 5C01 5Cclip filelist xml gt 一个 SPI 转串口驱动的
  • JavaScript动态加载CSS的三种方法

    JavaScript动态加载CSS的三种方法 CSDN Blog推出文章指数概念 文章指数是对Blog文章综合评分后推算出的 综合评分项分别是该文章的点击量 回复次数 被网摘收录数量 文章长度和文章类型 满分100 每月更新一次 如果你有很
  • 程序员也要学英语——印欧语音变规律总结

    目录 一 印欧语音变规律 二 口诀汇总 三 元音互换 a e i o u w y 1 词根 uni 一 统一 2 词根 tri 三 四 u v w 1 词根 nov 新 2 词根 vol 意愿 五 b p m f v 1 词根 bene 好
  • U3D打包DLL插件 DLL Builder

    前面的文章讲过如何通过cmd打包dll文件 文章链接 实际中 需求一般是很多文件需要打包到一个dll时 此时 一个一个添加打包吗 这里介绍一个很不错的插件 DLL Builder 商店地址 九块九 包邮 这是一个可视化的dll打包工具 可以
  • 小米SOAR

    小米soar工具安装 系统Ubuntu 18 04 更新下apt get包 防止报错 sudo apt get update sudo apt get install sudo apt get upgrade 安装Go语言 sudo apt
  • 如何在C语言中进行字符串的查找操作?

    首先 要进行字符串的查找操作 我们需要使用到C语言中的字符串函数 这些函数包括strlen strcmp strcat strcpy strstr 等等 它们可以实现字符串的长度计算 比较 拼接 复制 查找等操作 如果要在一个字符串中查找另
  • git clone和直接下载压缩包的区别

    目录 一 区别 一 区别 Git是公司开发中必不可少的一项基础技能 很多大型企业经常会有自己的内网 在内网直接下载压缩包后 写完业务后在进行远程ssh的绑定是无法绑定上的 因为公司内网对这种绑定作出了限制 而上司邀请你有开发权限后 直接使用
  • C++ main函数中参数argc和argv含义及用法( argument count和 argument vector)

    rgc 是 argument count的缩写 表示传入main函数的参数个数 argv 是 argument vector的缩写 注意 不是argument value的缩写 自己以前理解错了 表示传入main函数的参数序列或指针 并且第
  • Paxos与2PC

    Paxos与2PC Paxos协议和2PC协议在分布式系统中所起的作用并不相同 Paxos协议用于保证同一个数据分片的多个副本之间的数据一致性 当这些副本分布到不同的数据中心时 这个需求尤其强烈 2PC协议用于保证属于多个数据分片上的操作的
  • Winclone Pro for Mac(Windows分区备份还原工具)

    Winclone Pro for Mac一款Windows分区备份还原工具 winclone pro mac版保护您的Boot Camp Windows系统免受数据丢失以及将Boot Camp分区移动到新Mac的完整解决方案 Winclon
  • java返回值float_Java Float类的compare()方法与示例

    Float类compare 方法compare 方法在java lang包中可用 compare 方法用于检查给定两个浮点值的相等或不相等 换句话说 可以说此方法用于比较两个浮点值 compare 方法是一个静态方法 也可以使用类名进行访问
  • 爬虫手册05 异步爬虫

    异步爬虫 目标 例举asyncio和aiohttp模块的常规用法代码 关于协程概念参考 https blog csdn net weixin 40743639 article details 122394616 spm 1001 2014