我想从网站上爬取一些数据
========================
如何从网站爬取数据?
--------------------
实际上,\ **waifuc能爬取的网站远远不止Danbooru一个**
不过在正式开始之前,Narugo要介绍他的另一位老婆,可爱的小兔娘\ **阿米娅**\ ``amiya``\ ,同样来自\ **明日方舟**\ ``Arknights``
以下为Narugo发癫内容:你问我为什么有这么多老婆?众所周知,二次元爱好者的老婆有无限多个,她们都是我的天使\ **😍**
.. image:: amiya.png
:align: center
Zerochan
~~~~~~~~
`Zerochan `__\ 是一个包含图像平均质量较高的网站,我们可以使用极为简单的方式进行爬取
**当我们不需要大批量的获取图像,而只需要50张图像时**\ ,可以使用以下代码实现:
.. literalinclude:: zerochan_simple_50.py
:language: python
:linenos:
请注意,\ **此处使用**\ ``SaveExporter``\ **导出,而非之前的**\ ``TextureInversionExporter``\ **导出**\ ,关于它的作用将在本篇后续部分进行介绍
上述爬取到的图像数据将被导出到\ **指定的**\ ``./data/amiya_zerochan``\ **本地路径**\ 下,结果如下:
.. image:: zerochan_simple_50.png
:align: center
然而,我们会发现一个问题:
Zerochan上有较多的member-only的图像,我们需要登录后才能获取它们
为此我们可以\ **使用自己的用户名**\ ``username``\ 和\ **密码**\ ``password``\ 进行鉴权,以获得更多、更优质的图像,代码如下:
.. literalinclude:: zerochan_login_50.py
:language: python
:linenos:
再次运行,果然我们成功获取到了不少的member-only图像:
.. image:: zerochan_login_50.png
:align: center
不过我们又发现,这些图像很多分辨率并不高,边长超过1000像素的不多
这是因为\ **Zerochan会默认选用**\ ``large``\ **尺寸的图像**\ ,以提高下载速度
如果需要更大尺寸的图像,可以将\ **尺寸选择**\ ``select``\ 设置为\ ``full``\ ,就像这样:
.. literalinclude:: zerochan_login_50_full.py
:language: python
:linenos:
再再次运行后,得到的将全都是全尺寸的图像
然而,依然还存在一个问题:高质量图片中很多都是官方画作,而阿米娅作为游戏的女主角,更是常作为C位出现在多人图中
**我们实际上只需要仅包含她自己的图像**\ ,这当然是没问题,只需要将\ **严格搜索模式**\ ``strict``\ 设置为\ ``True``\ 即可:
.. literalinclude:: zerochan_login_50_full_strict.py
:language: python
:linenos:
再再再次运行,我们最终得到了来自Zerochan的高质量、全尺寸且均为阿米娅单人的图像,如下所示:
.. image:: zerochan_login_50_full_strict.png
:align: center
Danbooru
~~~~~~~~
理所当然,\ `Danbooru `__\也是可以轻松被waifuc爬取的,使用十分简单:
.. literalinclude:: danbooru_50.py
:language: python
:linenos:
以及,\ **在Danbooru及其类似网站可通过添加**\ ``solo``\ **关键词来直接筛选单人图像**\ ,以节省操作步骤,就像这样:
.. literalinclude:: danbooru_50_solo.py
:language: python
:linenos:
Pixiv
~~~~~
waifuc\ **支持对**\ `Pixiv `__\ **的多种爬取方式:关键词检索、用户检索以及各种排行榜爬取**
我们可以使用\ ``PixivSearchSource``\ 数据源来进行关键词检索方式的图像数据爬取,如下所示:
.. literalinclude:: pixiv_50.py
:language: python
:linenos:
我们也可以使用\ ``PixivUserSource``\ 数据源来进行检索方式的图像数据爬取,如下所示:
.. literalinclude:: pixiv_50_user.py
:language: python
:linenos:
我们还可以使用\ ``PixivRankingSource``\ 数据源来进行可选择的排行榜的图像数据爬取,如下所示:
.. literalinclude:: pixiv_50_ranking.py
:language: python
:linenos:
Anime-Pictures
~~~~~~~~~~~~~~
`Anime-Pictures `__\的图像数量不多,但是质量普遍很高
因此waifuc也同样支持对它的爬取,如下所示:
.. literalinclude:: anime_pictures_50.py
:language: python
:linenos:
Sankaku
~~~~~~~
`Sankaku `__\的图像数量庞大且种类很多
waifuc同样支持了它,如下所示:
.. literalinclude:: sankaku_50.py
:language: python
:linenos:
Gelbooru
~~~~~~~~
`Gelbooru `__\与Danbooru的内容很相似,但在一些特定内容上有更多图像
waifuc同样它支持的爬取,如下所示:
.. literalinclude:: gelbooru_50.py
:language: python
:linenos:
Duitang
~~~~~~~
`Duitang `__\是一个来自中国的网站,因其建站时间较长,也包含不少优质的图像
应中国用户的请求,Narugo为waifuc添加了针对堆糖(duitang)的支持,如下所示:
.. literalinclude:: duitang_50.py
:language: python
:linenos:
其余受支持的图像站
~~~~~~~~~~~~~~~~~~
除了上述的这些外,waifuc还支持了大量其他的图像站。\ **所有受支持图像站**\ 如下所示:
- `ATFBooruSource `__
- `AnimePicturesSource `__
- `DanbooruSource `__
- `DerpibooruSource `__
- `DuitangSource `__
- `E621Source `__
- `E926Source `__
- `FurbooruSource `__
- `GelbooruSource `__
- `Huashi6Source `__
- `HypnoHubSource `__
- `KonachanNetSource `__
- `KonachanSource `__
- `LolibooruSource `__
- `PahealSource `__
- `PixivRankingSource `__
- `PixivSearchSource `__
- `PixivUserSource `__
- `Rule34Source `__
- `SafebooruOrgSource `__
- `SafebooruSource `__
- `SankakuSource `__
- `TBIBSource `__
- `WallHavenSource `__
- `XbooruSource `__
- `YandeSource `__
- `ZerochanSource `__
(关于上述\ ``Source``\ 的更多信息和使用细节,详见waifuc源代码)
我想从多个网站上爬取数据
------------------------
在一些情况中,我们希望从多个网站获取图像数据
比如下面的情况中,我们需要从Danbooru上获取30张图像,再从zerochan上获取30张图像
为满足此类需求,waifuc提供了\ ``Source``\ 间的串并联操作,可以通过串联\ ``+``\ 和并联\ ``|``\ 将多个数据源进行集成
例如在上面的需求中,我们可以将Danbooru数据源和Zerochan数据源进行串联,形成新的数据源,如下所示:
.. literalinclude:: source_concat.py
:language: python
:linenos:
上述代码将先从Danbooru爬取30张图像,再从Zerochan爬取30张图像
这样,我们可以得到如下的数据集:
.. image:: source_concat.png
:align: center
除此之外,在部分情况下,我们可能并不会提前设计好从各个数据源爬取多少图像,而是希望能尽量多地从不同数据源爬取,并最终得到一个需要的总数量。在这种情况下,我们可以使用并联操作,如下所示:
.. literalinclude:: source_union.py
:language: python
:linenos:
在这一次爬取中,将从两个站中随机选择进行爬取,直至爬取到60张图像为止
因此实际上最终获得的数据集并不确定,以下数据集仅供参考:
.. image:: source_union.png
:align: center
所有的\ ``Source``\ 间也可以进行复杂的嵌套运算,以构建一个复杂的数据源:
.. literalinclude:: source_complex.py
:language: python
:linenos:
此处就构建了一个复杂的数据源
``s = s_zerochan[:50] + (s_db | s_pixiv)[:50]``\ ,具体功能为:
- 先从Zerochan上爬取50张图像
- 再从Danbooru和Pixiv上随机爬取,共计50张图像
因此这个数据源最终将爬取以Zerochan为主的100张图像
``Source``\ 的串并联操作还可以在\ ``attach``\ 方法之后进行,即进行预处理后,再进行串并联
例如:
.. literalinclude:: source_complex_attach.py
:language: python
:linenos:
上述代码的效果是:
- 从Zerochan和Danbooru两个网站上爬取图像
- Zerochan的图像需要进行去背景处理,而Danbooru上的不需要
- 两个数据源总计爬取60张图像
得到的结果如下所示,可以看到,zerochan的图像都进行了去背景处理:
.. image:: source_complex_attach.png
:align: center
通过以上演示可以了解,串并联是\ ``Source``\ 的一项重要特性,合理利用将让配置多样化且极富灵活性
为什么会有这么多json文件?
--------------------------
如果你坚持读到了这里,你应该会注意到示例图中的一个问题
上述所有使用\ ``SaveExporter``\ 进行保存的数据集,每个图像文件都有与其同名的json文件
你一定会感到好奇,这些json文件是做什么用的?我该如何关闭它们的生成?
该部分将对此一一作出解答
首先,我们打开一个其中的json文件\ ``.danbooru_6814120_meta.json``\ ,并查看里面的内容:
.. collapse:: A Sample Meta-Information JSON
.. literalinclude:: meta_json.json
:language: json
:linenos:
内容比较长,\ **简单来说,这是一个存储图像文件元数据**\ ``meta-information``\ **文件**
它包含了以下的信息:
- 来自danbooru网站的图像信息,即图像的tag、尺寸、ID、上传时间等
- 图像的url信息,即图像是从哪里被下载的
- 图像的命名信息,即图像将被保存为什么文件名
- 图像的tag信息,即当生成训练用的数据集时,其tag将包含哪些
这些信息在一些处理环节中,将发挥其应有的作用
例如tag信息,生成该信息需要从网站进行爬取,或者使用tagger进行打标,而该信息将在产生LoRA训练数据集时进行写入
因此在waifuc中,默认对json文件进行保存,并且可以使用\ ``SaveExporter``\ 进行保存
为了充分利用这些元数据,我们\ **可以使用**\ ``LocalSource``\ **将包含json文件的本地数据集通过**\ ``SaveExporter``\ **再次加载**\ :
.. literalinclude:: local.py
:language: python
:linenos:
以上代码可以将包含元数据的本地数据集再次载入,并按照LoRA训练数据集的格式进行再次保存,即只保留存储标注信息的txt文件
处理后的数据集如下所示:
.. image:: local_to_dataset.png
:align: center
.. note::
- \ ``LocalSource``\ **对所有本地的数据集都可进行加载,并不一定需要元数据**
- 若没有json文件,得到的图像数据将不包含初始元数据,这意味着tag等信息必须重新生成
- \ ``LocalSource``\ **作为一种**\ ``Source``\ **,也可以进行串并联操作,因此你可以同时使用来自网络和本地的图像构建数据集**
当你确定只需要图像,不需要任何元数据时,设置参数\ ``no_meta``\为\ ``True``\来实现这一点:
.. literalinclude:: save_no_meta.py
:language: python
:linenos:
这样的代码将不会保存任何json文件,将只爬取50张图像,如下所示:
.. image:: save_no_meta.png
:align: center
我不想将图像保存到硬盘上,如何直接使用它们?
--------------------------------------------
你可能不希望将图像文件缓存到硬盘上,而是直接在内存中处理以节省时间
.. literalinclude:: iterate_usage.py
:language: python
:linenos:
没错,\ **所有**\ ``Source``\ **都是可以作为List进行遍历操作的**
而其中的item,其类型定义如下:
.. literalinclude:: item_definition.py
:language: python
:linenos:
不难发现,每一个item的结构十分简单,包含一个\ ``PIL.Image``\ 结构的图像对象和一个用于存储元信息的\ ``meta``\项。
获取到item项后,你将可以自行使用其图像对象和元数据定制所需要的操作。