Python异步编程--获取girlypic写真集

news2024/11/25 12:35:34

前言

在日常生活中,无论是网络配置、文件整理、web开发还是工具,时常用到Python写些脚本。

这次主要是分享下异步编程的经验,就拿获取girlypic的图片举例吧,也希望能给一些同学带来思考。

  • 使用argparse而不是os.args,这个库能够优雅地获取命令行参数,不再需要os.args判断个数或者类型。
  • 使用pathlib而不是os.path,这个库能够高效地处理各种文件操作,创建、修改、删除、路径拼接等。
  • 使用logging而不是print,个人更加习惯用日志的方式打印信息。
  • 使用aiohttp而不是requests,当你决定用异步的方式发送网络请求时,就用这个库吧。
  • 使用aiofiles而不是open,当你决定用异步的方式读写文件时,就用这个库吧。
  • 使用lxml,这个库能够使用Xpath语法帮助我们解析html内容。
  • 使用asyncio.create_task而不是for循环,当一组任务不是顺序相关时,不必循环await执行,通过创建任务的方式异步执行。
  • 使用类型提示,标注变量的类型,方便IDE检索。

以上是常用的库或者提示,没有好坏之分,主要是看个人的习惯,一旦一处异步,那就处处异步

Python版本

当前稳定版本是:3.10.11

Python依赖

aiohttp==3.8.6
aiofiles==23.2.1
lxml==4.9.3

Python源码

import asyncio
import logging
import argparse
from pathlib import Path

import aiohttp
import aiofiles
from lxml import etree

logger = logging.getLogger()
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter)
logger.addHandler(console)

PROXY = "http://127.0.0.1:10808"
SAVE_FOLDER = Path("Downloads")
PICTURE_HOST = "https://girlygirlpic.com"
PICTURE_GATHER = PICTURE_HOST + "/ax/"
PICTURE_SEARCH = PICTURE_HOST + "/sx/"
PICTURE_URL = '//div[@class="post-media-body"]//a[@class="figure-link os-lightbox-activator"]/@href'
ALBUM_NAMES = '//div[@class="post-content-body"]/h4[@class="post-title entry-title"]/a[@class="on-popunder"]'
HEADER = {
    "Origin": PICTURE_HOST,
    "Connection": "close",
    "Cookie": "_user_language=Cn",
    "X-Requested-With": "XMLHttpRequest",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0"
}

async def download_picture(url: str, save_folder: Path) -> None:
    async with aiohttp.ClientSession() as session:
        try:
            async with session.get(url, proxy=PROXY, headers=HEADER) as response:
                picture_name = url[url.rfind("/") + 1:]
                async with aiofiles.open(save_folder / picture_name, "wb") as handle:
                    async for chunk in response.content.iter_chunked(1024):
                        await handle.write(chunk)
        except Exception as exception:
            logger.error(f"{exception} [URL] {url}")

async def parse_album(url: str, save_folder: Path) -> None:
    album_id = url[url.rfind("/") + 1:]
    header = {**HEADER, **{"Referer": url}}
    async with aiohttp.ClientSession() as session:
        requests_body = {"album_id": album_id}
        async with session.post(PICTURE_GATHER, json=requests_body, proxy=PROXY, headers=header) as response:
            html_content = await response.text()
            image_href = etree.HTML(html_content).xpath(PICTURE_URL)
            logger.info(f"{len(image_href):03d} photos of album [{save_folder.name}]")
            task_list = [asyncio.create_task(download_picture(pic_url, save_folder)) for pic_url in image_href]
            await asyncio.wait(task_list) if len(task_list) > 0 else None
            logger.info(f"album saved [{save_folder.name}]")

async def get_albums(name: str) -> None:
    async with aiohttp.ClientSession() as session:
        requests_body = {"search_keys_tag": name}
        async with session.post(PICTURE_SEARCH, json=requests_body, proxy=PROXY, headers=HEADER) as response:
            html_content = await response.text()
            album_content = etree.HTML(html_content).xpath(ALBUM_NAMES)
            logger.info(f"{len(album_content):03d} albums about {name}")
            task_list = []
            for album in album_content:
                href = album.get("href")
                text = album.text
                save_folder = SAVE_FOLDER / name / text
                save_folder.mkdir(parents=True) if not save_folder.exists() else None
                task_list.append(asyncio.create_task(parse_album(href, save_folder)))
            await asyncio.wait(task_list) if len(task_list) > 0 else None

async def main(names: [str]) -> None:
    await asyncio.wait([asyncio.create_task(get_albums(name)) for name in names])
    logger.info("done")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="download pictures")
    parser.add_argument("name", type=str, nargs='+', help="girls name list")
    args = parser.parse_args()
    asyncio.run(main(args.name))

其中PICTURE_HOST就是域名,需要科学访问,所以PROXY自己配置吧。

运行方法很简单:python main.py xxxx xxxx xxxx,其中xxxx为姓名,多个人名按照空格隔开。

获取完毕后会在当前创建一个Downloads目录,图片会按照姓名以及相册名归类在里面。

运行结果

这就是异步的魅力,同步的方式只能一次发送一个请求,然后阻塞在网络IO上,异步则会在这种情况下让出CPU资源执行其他的代码。

效果图不方便放,大家可以自己试试

图片过多,访问过于频繁时,请求有可能会被BAN,所以可以适当地延迟下载任务,由于是异步,就不要用time.sleep()了,而是要用asyncio.sleep()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1178079.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pytorch直线拟合

目录 1、数据分析 2、pytorch直线拟合 1、数据分析 直线拟合的前提条件通常包括以下几点: 存在线性关系:这是进行直线拟合的基础,数据点之间应该存在一种线性关系,即数据的分布可以用直线来近似描述。这种线性关系可以是数据点…

86.Linux系统下复制进程fork(逻辑地址和物理地址)

目录 fork复制进程 逻辑地址和物理地址 fork复制进程 fork 是一个系统调用,在 Linux/Unix 系统中用于创建一个新的进程,新进程称为子进程。子进程是父进程的副本,它从父进程那里继承了大部分属性和资源,包括代码、数据、打开的文…

【逗老师的无线电】Debian Linux手工编译安装MMDVM

看我干了啥,在Vmware里面装了一个Debian Linux并且运行了MMDVMHost,来支持业余无线电通联 开始之前先举个手,有多少朋友能分清MMDVM和Pi-Star关系的? MMDVM、Pi-Star和树莓派的关系 咱们先科普一下这个小知识点。各位HAM们应…

Python基础(第五期): python数据容器(序列) 列表 集合 元素 字符串 字典 序列遍历操作

python基础专栏 python基础(第五期) 文章目录 python基础(第五期)数据容器一、列表1、列表的定义2、列表的下标索引 3、列表的(添加)方法3.1 列表的查询方法3.2 修改特定下标索引的值3.3 列表指定位置插入元素3.3 列表指定元素的追…

自动驾驶高效预训练--降低落地成本的新思路(AD-PT)

自动驾驶高效预训练--降低落地成本的新思路 1. 之前的方法2. 主要工作——面向自动驾驶的点云预训练2.1. 数据准备 出发点:通过预训练的方式,可以利用大量无标注数据进一步提升3D检测 https://arxiv.org/pdf/2306.00612.pdf 1. 之前的方法 1.基于对比学…

setTimeout和setImmediate以及process.nextTick的区别?

目录 前言 setTimeout 特性和用法 setImmediate 特性和用法 process.nextTick 特性和用法 区别和示例 总结 在Node.js中,setTimeout、setImmediate和process.nextTick是用于调度异步操作的三种不同机制。它们之间的区别在于事件循环中的执行顺序和优先级。…

django安装数据库

使用pip安装django pip3 install django注意我使用的是python3所以用pip3安装,如需安装指定版本 django ..* 检测是否安装成功,不报错,则安装成功 # python3 # import django下边这是报错的 django迁移数据库 再mysql中简历数据库 CREATE DATABA…

COOHOM通过采用亚马逊云科“专库专用”的方式,为云原生的构建提供稳定的数据支撑

全球化浪潮下,面对全球化业务发展带来的新需求与新挑战,越来越多的企业开启了云原生构建旅程,以推动业务系统快速迭代,为国际业务的拓展打下坚实的基础。COOHOM是杭州群核信息技术有限公司旗下的国际化品牌。为全球企业和个人提供…

au怎么把音乐和人声单独分离出来?分享最简单的方法!

把音乐和人声单独分离,对于音频处理和后期制作来说,可以方便地对人声或音乐进行单独的处理和编辑,以达到更好的效果。下面介绍了怎么把利用AU音乐和人声单独分离出来的详细步骤。 一、AU 1、把自己需要处理的那首歌copy到桌面,再…

npm install:sill idealTree buildDeps

执行npm install,卡在 sill idealTree buildDeps PS D:\workspace-groovy\attendance-india-web> npm install -g cnpm --registryhttps://registry.npm.taobao.org [..................] / idealTree:node_global: sill idealTree buildDeps[.................…

BUUCTF 隐藏的钥匙 1

BUUCTF:https://buuoj.cn/challenges 题目描述: 路飞一行人千辛万苦来到了伟大航道的终点,找到了传说中的One piece,但是需要钥匙才能打开One Piece大门,钥匙就隐藏在下面的图片中,聪明的你能帮路飞拿到钥匙&#xff…

视频编辑软件Corel VideoStudio 会声会影2024中文剪辑使用教程

会声会影(Corel VideoStudio)2024为加拿大Corel公司发布的一款功能丰富的视频编辑软件。会声会影2023简单易用,具有史无前例的强大功能,拖放式标题、转场、覆叠和滤镜,色彩分级、动态分屏视频和新增强的遮罩创建器&…

​软考-高级-信息系统项目管理师教程 第四版【第15章-项目风险管理-思维导图】​

软考-高级-信息系统项目管理师教程 第四版【第15章-项目风险管理-思维导图】 课本里章节里所有蓝色字体的思维导图

多线程JUC 第2季 多线程的原子性

一 多线程原子性 1.1 基本数据类型原子 atomicInteger, atomicLong,atomicBoolean 代码 package com.ljf.thread.atomic;import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger;class MyNumber {AtomicInt…

YoloV5训练V3Det数据集实战

摘要 V3Det:一个庞大的词汇视觉检测数据集,在大量真实世界图像上具有精确注释的边界框,其包含13029个类别中的245k个图像(比LVIS大10倍),数据集已经开源! 图片的数量比COCO多一些,…

【Redis】hash数据类型-常用命令

文章目录 前置知识常用命令HSETHGETHEXISTSHDELHKEYSHVALSHGETALLHMGET关于HMSETHLENHSETNXHINCRBYHINCRBYFLOAT 命令小结 前置知识 redis自身就是键值对结构了,哈希类型是指值本⾝⼜是⼀个键值对结构,形如key"key",value{{field1…

哪一波最容易亏钱,昂首资本这样讲

有交易者咨询anzo capital昂首资本,按照波浪理论最容易亏钱是在第几波,通过调查得知80%的错误发生在第四波。所以对哪一波最容易亏钱,很有可能就是第四波。当然了如果能准确的判断第四波时,也可能获得相当丰厚的利润。 第四波通…

8 mysql中的索引2

一、索引的种类 1、 B树索引 1.**每个索引就是一颗B树**,二级索引不包含行记录的全部数据 2.叶子节点除了包含键值以外,每个叶子节点中的索引行中还包含了一个书签( bookmark) 3.B平衡树是一颗查找树,B树的叶子节点用来放数据的,并且所有叶…

仿mudou库one thread one loop式并发服务器

目录 1.实现目标 2.HTTP服务器 实现高性能服务器-Reactor模型 模块划分 SERVER模块: HTTP协议模块: 3.项目中的子功能 秒级定时任务实现 时间轮实现 正则库的简单使用 通⽤类型any类型的实现 4.SERVER服务器实现 日志宏的封装 缓冲区Buffer…

软件设计不是CRUD(4):耦合度的强弱(上)

在讨论如何稳定系统内各模块的分层设计前, 本文先介绍一下目前判断各模块间耦合度强弱的度量方式。这些度量方式,在实际工作中读者应该都涉及过,只是可能没有去做详细的划分归类。 1、模块间耦合强度度量 模块间的耦合强度分为以下几种&…