python 异步协程爬虫-半次元图片

python 异步协程爬虫-半次元图片,第1张

python 异步协程爬虫-半次元图片
  • 1. 页面分析
  • 2.代码大体构思
  • 3.源码分析
    • 3.1 完成效果
  • 4.异步协程的优势
  • 5.难点分析
  • 6.可扩展性
    • 欢迎私信或评论区交流

爬取网址 : https://www.bcy.net/item/detail/7086637143778401318
1、免职申明 :内容仅供参考学习使用,侵删
2、图片可能存在侵权风险均打码处理 望谅解

1. 页面分析

1.查看原页面

2.查看响应数据源码页面

3.查看是否为ajax异步加载

经判断非异步加载
翻看源代码,发现图片来源于源码中js渲染如下图:

太长截不完,明白就行

2.代码大体构思

懒得画流程图了将就看【笑】
实现很简单

"""
函数共6个:
get_img_src(url) # 获取网页标题及图片地址
check_title(title) # 修改文件夹标题以符合windows文件夹的命名规范
download_img(session, url, path) # 异步函数爬取图片 
run_tasks(task_list) # 执行异步任务
error_download(url, path) # 异步任务错误的图片重新爬取
main(url) # 主函数
"""
3.源码分析
# 目标 :https://www.bcy.net/item/detail/7086637143778401318
import os
import re
import time
import js2py
import requests
from bs4 import BeautifulSoup
import ua
import asyncio
import aiohttp

error_src_list = list()


def get_img_src(url):
    response = requests.get(url, headers=ua.headers())
    response.encoding = 'utf-8'
    html = response.text
    soup = BeautifulSoup(html, 'lxml')
    title = check_title(soup.find('title').string)
    script = 'var window = Object();%s;function show(){return window.__ssr_data}' % soup.find_all('script')[-5].string
    js = js2py.EvalJs()
    js.execute(script)
    result = js.show()
    img_src_list = [i['original_path'] for i in result['detail']['post_data']['multi']]
    return [title, img_src_list]
"""
get_img_src(url)
获取网页源代码
BeautifulSoup()解析网页
script 重构js代码
运行js代码{
	可以使用的方法:
		1.调用node.js :麻烦
		2.使用execjs库 :问题:兼容性不佳,编码问题,速度慢
		3.使用js2py库:问题:兼容性不佳, 速度中等
		......
		还有很多 自己搜索
}
"""


def check_title(title):
    rep = re.compile(r'[\\/:*?"<>|\r\n]+')
    change_name = rep.findall(title)
    if change_name:
        name = ''
        for i in change_name:
            name = title.replace(i, "_")
        return name
    else:
        return title
"""
check_title(title)
修改标题
正则查找,遍历修改
"""


async def download_img(session, url, path):
    async with semaphore:
        async with session.get(url, headers=ua.headers()) as response:
            if response.status == 200:
                with open(path, 'wb') as f:
                    while True:
                        buffer = await response.content.read(4096)
                        if not buffer:
                            break
                        f.write(buffer)
                        f.flush()
                    print('成功 : ' + url)
            else:
                print('失败 : ' + url)
                error_src_list.append([url, path])
"""
def download_img(session, url, path)
异步函数不会的自学
"""


async def run_tasks(task_list):
    async with aiohttp.ClientSession() as session:
        title = task_list[0]
        try:
            os.mkdir(f'./img/{title}')
        except os.error:
            pass
        urls = task_list[1]
        tasks = [download_img(session, url, './img/{}/{}.jpg'.format(title, p)) for p, url in enumerate(urls)]
        await asyncio.wait(tasks)
"""
run_tasks(task_list)
异步函数
aiohttp库重点
异步中无法使用requests库
不会的自学
"""


def error_download(url, path):
    response = requests.get(url, headers=ua.headers(), stream=True)
    if response.status_code == 200:
        with open(path, 'wb') as f:
            for data in response.iter_content(4096):
                f.write(data)
                f.flush()
        print('重试成功 : ' + url)
    else:
        time.sleep(5)
        error_download(url, path)
"""
error_download(url, path)
失败后重新下载
异步高并发,同时请求大量数据会失败
失败后添加到error_src_list列表异步协程任务完成后调用普通下载
"""


def main(url):
    tasks_list = get_img_src(url)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run_tasks(tasks_list))
    for url, path in error_src_list:
        error_download(url, path)
"""
main()
获取任务列表运行协程任务
"""

if __name__ == '__main__':
    semaphore = asyncio.Semaphore(50) # 控制任务并发数
    main('https://www.bcy.net/item/detail/7086637143778401318')
3.1 完成效果

4.异步协程的优势

协程本质上是个单进程,协程相对于多进程来说,无需线程上下文切换的开销,无需原子 *** 作锁定及同步的开销,编程模型也非常简单。
我们可以使用协程来实现异步 *** 作,比如在网络爬虫场景下,我们发出一个请求之后,需要等待一定的时间才能得到响应,但其实在这个等待过程中,程序可以干许多其他的事情,等到响应得到之后才切换回来继续处理,这样可以充分利用 CPU 和其他资源,这就是异步协程的优势。

5.难点分析

1.寻找图片出处

2.解析源码运行js代码获得json数据,提取列表

3.异步协程的实现及错误后的重试

6.可扩展性

可以把总任务数量增加
爬取日榜, 周榜,单独标签爬取

# 伪代码
# 一个函数 爬取日榜,周榜的链接地址
# 一个函数 循环 给main()函数传递任务

还可以连接数据库传入任务给主函数

# 伪代码
# 一个函数 连接数据库读取数据
# 一个函数 循环 给main()传递任务
欢迎私信或评论区交流

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/730921.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-27
下一篇 2022-04-27

发表评论

登录后才能评论

评论列表(0条)

保存