目录
详看:python爬虫基础--json数据和jsonpath--多线程原理_我还可以熬_的博客-CSDN博客
终于考完试了,自由了哈哈哈哈哈
本来早该完成的这篇,然后期间考试,耽误了很久!!!今天考完了!!!!!!!!!
知识点回顾
json数据
jsonpath的使用
多线程原理
详看:python爬虫基础--json数据和jsonpath--多线程原理_我还可以熬_的博客-CSDN博客
下面的例子均用虎扑网为例!!!
多线程
多线程--方法版
需要用到模块:
import requests
from fake_useragent import UserAgent
from time import sleep
from queue import Queue
from threading import Thread
定义一个函数spider()
判断URL网站是否不为空:
while not url_queue.empty():
url = url_queue.get()
在后面要判断URL网站是否能访问成功:
if resp.status_code == 200:
print(f'成功获取了:{url}')
另外为了不过于频繁的在短时间的产生过多的访问,要添加一个sleep:
sleep(3)
使用线程来处理 URL队列中的url,然后将url返回的结果保存在另一个队列中,其他线程读取数据,并写入文件中。
if __name__ == '__main__':
url_queue = Queue()
for i in range(1,11):
url = f'https://www.hupu.com/home/v1/news?pageNo={i}&pageSize=50'
url_queue.put(url)
for i in range(3):
# 创建线程
t = Thread(target=spider)
#启动线程
t.start()
完整代码如下:
import requests
from fake_useragent import UserAgent
from time import sleep
from queue import Queue
from threading import Thread
def spider():
'''
从队列里获取url,并且爬取
'''
while not url_queue.empty():
url = url_queue.get()
# 获取数据
headers={
'User-agent':UserAgent().chrome
}
resp = requests.get(url,headers=headers)
if resp.status_code == 200:
print(f'成功获取了:{url}')
sleep(3)
if __name__ == '__main__':
url_queue = Queue()
for i in range(1,11):
url = f'https://www.hupu.com/home/v1/news?pageNo={i}&pageSize=50'
url_queue.put(url)
for i in range(3):
# 创建线程
t = Thread(target=spider)
#启动线程
t.start()
效果如下:
多线程--类版
跟类版跟方法版其实没有什么区别,就是把内容放入一个类中。
import requests
from fake_useragent import UserAgent
from queue import Queue
from threading import Thread
from time import sleep
class MyThead(Thread):
def run(self):
'''
从队列里获取url,并且爬取
'''
while not url_queue.empty():
url = url_queue.get()
# 获取数据
headers={
'User-agent':UserAgent().chrome
}
resp = requests.get(url,headers=headers)
if resp.status_code == 200:
print(f'成功获取了:{url}')
sleep(3)
if __name__ == '__main__':
url_queue = Queue()
for i in range(1,11):
url = f'https://www.hupu.com/home/v1/news?pageNo={i}&pageSize=50'
url_queue.put(url)
for i in range(3):
# 创建进程
t = MyThead()
# 启动进程
t.start()
跟方法版的输出结果是一样的。
多进程
提升爬虫效率除了多线程以外还有多进程,multiprocessing是python的多进程管理包,和threading.Thread类似。
multiprocessing模块
multiprocessing模块可以让程序员在给定的机器上充分的利用CPU
在multiprocessing中,通过创建Process对象生成进程,然后调用它的start()方法。
Manager类,实现数据共享
在使用并发设计的时候最好尽可能的避免共享数据,尤其是在使用多进程的时候。 如果你真有需要 要共享数据,可以使用由Manager()返回的manager提供list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value and Array类型的支持
进程池的使用
-
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。
-
进程池中有两个方法:
- apply同步执行-串行
- apply_async异步执行-并行(推荐使用)
多进程--方法版
需要用到的模块:
import requests
from fake_useragent import UserAgent
from time import sleep
from multiprocessing import Process,Manager
爬虫主体内容与多线程的基本一致:
def spider(url_queue):
'''
从队列里获取url,并且爬取
'''
while not url_queue.empty():
url = url_queue.get()
# 获取数据
headers={
'User-agent':UserAgent().chrome
}
resp = requests.get(url,headers=headers)
if resp.status_code == 200:
print(f'成功获取了:{url}')
sleep(3)
创建进程列表,启动列表和获取数据:
if __name__ == '__main__':
url_queue = Manager().Queue()
for i in range(1,11):
url = f'https://www.hupu.com/home/v1/news?pageNo={i}&pageSize=50'
url_queue.put(url)
# 创建一个进程列表
all_process = []
for i in range(3):
# 创建进程
p = Process(target=spider,args=(url_queue,))
#启动进程
p.start()
# 将每个列表增加到进程列表中
all_process.append(p)
# 等待所有进程结束
for p in all_process:
p.join()
完整代码如下:
import requests
from fake_useragent import UserAgent
from time import sleep
from multiprocessing import Process,Manager
def spider(url_queue):
'''
从队列里获取url,并且爬取
'''
while not url_queue.empty():
url = url_queue.get()
# 获取数据
headers={
'User-agent':UserAgent().chrome
}
resp = requests.get(url,headers=headers)
if resp.status_code == 200:
print(f'成功获取了:{url}')
sleep(3)
if __name__ == '__main__':
url_queue = Manager().Queue()
for i in range(1,11):
url = f'https://www.hupu.com/home/v1/news?pageNo={i}&pageSize=50'
url_queue.put(url)
# 创建一个进程列表
all_process = []
for i in range(3):
# 创建进程
p = Process(target=spider,args=(url_queue,))
#启动进程
p.start()
# 将每个列表增加到进程列表中
all_process.append(p)
# 等待所有进程结束
for p in all_process:
p.join()
多进程-- 进程池版
跟方法版差不多,这里创建三个进程:
import requests
from fake_useragent import UserAgent
from time import sleep
from multiprocessing import Pool,Manager
def spider(url_queue):
'''
从队列里获取url,并且爬取
'''
while not url_queue.empty():
url = url_queue.get()
# 获取数据
headers={
'User-agent':UserAgent().chrome
}
resp = requests.get(url,headers=headers)
if resp.status_code == 200:
print(f'成功获取了:{url}')
sleep(3)
if __name__ == '__main__':
url_queue = Manager().Queue()
for i in range(1,11):
url = f'https://www.hupu.com/home/v1/news?pageNo={i}&pageSize=50'
url_queue.put(url)
# 创建进程池
pool = Pool(3)
#开启进程
pool.apply_async(func=spider,args=(url_queue))
pool.apply_async(func=spider,args=(url_queue))
pool.apply_async(func=spider,args=(url_queue))
# 等待所有进程结束
pool.close()
# 将每个列表增加到进程列表中
pool.join()
协程
网络爬虫速度效率慢,多部分在于阻塞IO这块(网络/磁盘)。在阻塞时,CPU的中内核是可以处理别的非IO操作。因此可以考虑使用协程来提升爬虫效率,这种操作的技术就是协程。
可以让阻塞的子程序让出CPU给可以执行的子程序
一个进程包含多个线程,一个线程可以包含多个协程
多个线程相对独立,线程的切换受系统控制。 多个协程也相对独立,但是其切换由程序自己控制
安装第三方模块
pip install aiohttp
好~这里我们已经成功安装了:
接下来我们看看这个库里边的一些常用方法:
剩下的就去官网看吧
属性或方法 | 功能 |
---|---|
aiohttp.ClientSession() | 获取客户端函数 |
session.get(url) | 发送get请求 |
seesion.post(url) | 发送post请求 |
resp.status | 获取响应状态码 |
resp.url | 获取响应url地址 |
resp.cookies | 获取响应cookie内容 |
resp.headers | 获取响应头信息 |
resp.read() | 获取响应bytes类型 |
resp.text() | 获取响应文本内容 |
具体使用:
import aiohttp
import asyncio
async def first():
async with aiohttp.ClientSession() as session: # aiohttp.ClientSession() == import requests 模块
async with session.get('http://httpbin.org/get') as resp:
rs = await resp.text()
print(rs)
headers = {'User-Agent':'aaaaaa123'}
async def test_header():
async with aiohttp.ClientSession(headers= headers) as session: # aiohttp.ClientSession() == import requests 模块
async with session.get('http://httpbin.org/get') as resp:
rs = await resp.text()
print(rs)
async def test_params():
async with aiohttp.ClientSession(headers= headers) as session: # aiohttp.ClientSession() == import requests 模块
async with session.get('http://httpbin.org/get',params={'name':'bjsxt'}) as resp:
rs = await resp.text()
print(rs)
async def test_cookie():
async with aiohttp.ClientSession(headers= headers,cookies={'token':'sxt123id'}) as session: # aiohttp.ClientSession() == import requests 模块
async with session.get('http://httpbin.org/get',params={'name':'bjsxt'}) as resp:
rs = await resp.text()
print(rs)
async def test_proxy():
async with aiohttp.ClientSession(headers= headers,cookies={'token':'sxt123id'}) as session: # aiohttp.ClientSession() == import requests 模块
async with session.get('http://httpbin.org/get',params={'name':'bjsxt'},proxy = 'http://name:pwd@ip:port' ) as resp:
rs = await resp.text()
print(rs)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(test_cookie())
-------------------------------2023.3.2-----------------------------