用户工具

站点工具


niconico:shunga
ニコニコ春画
URL https://seiga.nicovideo.jp/shunga/
成立于 2011-8
关闭于 2025-1-29
别名 NicoNico Shunga
拥有者 DWANGO Co., Ltd.
数据量 ~140GiB
project code saveweb/niconico_shunga

ニコニコ春画

ニコニコ春画(NicoNico Shunga)是 ニコニコ静画(NicoNico Seiga)中的 R-15 分类,于 2025-1-29 14:00 (UTC+9) 删除1)

Q.「ニコニコ春画」とはなんですか?
A.
ニコニコ静画のイラストコーナー内にあるサービスです。「ニコニコ春画」では、投稿時にR-15カテゴリが設定されたイラストや、過度に性的・過激な表現が含まれると判断されたイラストが掲載されます。 2)

另见:Niconico#Nico_Nico_Shunga

列出 img_id

https://seiga.nicovideo.jp/shunga/list?sort=image_created&page={page}

遍历 page 拿到所有 shunga 的 img_id (seiga_id)。

缩略图

Shunga 的缩略图没有任何访问限制,随便跑128并发。

https://lohas.nicoseiga.jp/thumb/{img_id}{size}

size 为 l 即为最大的缩略图。

原图

需要带登录 Cookies 以及 jp ip 访问

https://seiga.nicovideo.jp/image/source/{img_id}

访问后会被 30X 到类似 https://lohas.nicoseiga.jp/o/1c8dd1f72bdc7aa3f0684aa0379e31c5bf9c2782/1737552023/5293773 的页面, 1c8dd1f72bdc7aa3f0684aa0379e31c5bf9c2782 是 token,1737552023 是 token 过期时间,5293773 是 img_id 。

这个页面是用一个叫 illust_view_big 的 div 来显示原图的。

<div class="illust_view_big"
  data-src="<https://lohas.nicoseiga.jp/priv/1c8dd1f72bdc7aa3f0684aa0379e31c5bf9c2782/1737552023/5293773>"
  data-watch_url="<https://seiga.nicovideo.jp/seiga/im5293773>"
></div>

把页面 URL 中的 /o/ 替换为 /priv/ ,跟 data-src 的链接是一样的。

/priv/ 原图的 endpoint 有 ratelimit,单 ip 实测 6s/q 能稳定跑。

PC 详情页

https://seiga.nicovideo.jp/seiga/im{img_id} 的形式,随便跑128并发。

Zeno Patches

bug1: Zeno v1 的 --cookies 功能没有实现(bug2: 总是加载 ./cookies.txt,忽略了用户指定的路径。懒得修了)。

diff --git a/internal/pkg/crawl/capture.go b/internal/pkg/crawl/capture.go
index 0e7308c8..3e6fc594 100644
--- a/internal/pkg/crawl/capture.go
+++ b/internal/pkg/crawl/capture.go
@@ -207,6 +207,14 @@ func (c *Crawl) Capture(item *queue.Item) error {
                req.Header.Set("Referer", utils.URLToString(item.ParentURL))
        }
 
+       // apply c.Client.Jar to request
+       if c.Client.Jar != nil {
+               c.Log.Info("Cookie jar applied", "cookies", c.Client.Jar.Cookies(item.URL), "url", utils.URLToString(item.URL))
+               for _, cookie := range c.Client.Jar.Cookies(item.URL) {
+                       req.AddCookie(cookie)
+               }
+       }
+
        req.Header.Set("User-Agent", c.UserAgent)
 
        // Execute site-specific code on the request, before sending it

Zeno v1 的通用外链提取器没有覆盖到 div:data-src 和 div:data-watch_url 。

diff --git a/internal/pkg/crawl/assets.go b/internal/pkg/crawl/assets.go
index 9aaa90eb..87f7a157 100644
--- a/internal/pkg/crawl/assets.go
+++ b/internal/pkg/crawl/assets.go
@@ -232,6 +232,24 @@ func (c *Crawl) extractAssets(base *url.URL, item *queue.Item, doc *goquery.Docu
                }
        })
 
+       //      <div class="illust_view_big"
+       //     data-src="<https://lohas.nicoseiga.jp/priv/1c8dd1f72bdc7aa3f0684aa0379e31c5bf9c2782/1737552023/5293773>"
+       //     data-watch_url="<https://seiga.nicovideo.jp/seiga/im5293773>"
+       //   ></div>
+       if !utils.StringInSlice("div", c.DisabledHTMLTags) {
+               doc.Find("div").Each(func(index int, item *goquery.Selection) {
+                       dataSrc, exists := item.Attr("data-src")
+                       if exists {
+                               rawAssets = append(rawAssets, dataSrc)
+                       }
+
+                       // dataWatchURL, exists := item.Attr("data-watch_url")
+                       // if exists {
+                       //      rawAssets = append(rawAssets, dataWatchURL)
+                       // }
+               })
+       }
+
        // Extract assets on the page (images, scripts, videos..)
        if !utils.StringInSlice("img", c.DisabledHTMLTags) {
                doc.Find("img").Each(func(index int, item *goquery.Selection) {

对 /priv/ 的图链做全局限速。

diff --git a/internal/pkg/crawl/assets.go b/internal/pkg/crawl/assets.go
index 9aaa90eb..fd13eabd 100644
--- a/internal/pkg/crawl/assets.go
+++ b/internal/pkg/crawl/assets.go
@@ -20,9 +20,26 @@ import (
 var backgroundImageRegex = regexp.MustCompile(`(?:\\(['"]?)(.*?)(?:['"]?\\))`)
 var urlRegex = regexp.MustCompile(`(?m)url\\((.*?)\\)`)
 
+var NicoNicoLock = &sync.Mutex{}
+var LastNicoNicoArchivedAt = time.Now()
+
+const RATE_LIMIT_NICONICO = time.Duration(6 * time.Second)
+
 func (c *Crawl) captureAsset(item *queue.Item, cookies []*http.Cookie, headers map[string]string) error {
        var resp *http.Response
 
+       if niconico.IsLohasImagePrivUrl(utils.URLToString(item.URL)) {
+               NicoNicoLock.Lock()
+               timeToSleepDuration := RATE_LIMIT_NICONICO - time.Since(LastNicoNicoArchivedAt)
+               if timeToSleepDuration > 0 {
+                       c.Log.Info("Sleeping for", "timeToSleepDuration", timeToSleepDuration)
+                       time.Sleep(timeToSleepDuration)
+               }
+
+               LastNicoNicoArchivedAt = time.Now()
+               NicoNicoLock.Unlock()
+       }
+
        // Prepare GET request
        req, err := http.NewRequest("GET", utils.URLToString(item.URL), nil)
        if err != nil {

存档过程

遍历得到大概 114500+ 个 img_id,先把缩略图存了。

CHUNGA-THUMB-20250121180740887-crawling


由于原图有 rate-limit ,算下来单机跑需要 (114500*6)/3600/24 = 8 days 才能存完原图,时间来不及。

翻了一会儿,发现 Gcore 卖非常便宜的按小时收费的 JP VPS,于是开了 7 台 (加上群友的两台 vultr JP),每台都加进 tailscale,然后按顺序从 {1..9} 设 IP,然后 sing-box 各自在 7690 端口上开个 socks 代理。

sudo apt update
sudo apt install curl htop tmux -y
 
# curl <https://github.com/yzqzss.keys> >> .ssh/authorized_keys
 
curl -fsSL <https://tailscale.com/install.sh> | sh && sudo tailscale up --auth-key=xxxxxxxx
 
sudo curl -fsSL <https://sing-box.app/gpg.key> -o /etc/apt/keyrings/sagernet.asc
sudo chmod a+r /etc/apt/keyrings/sagernet.asc
echo "deb [arch=`dpkg --print-architecture` signed-by=/etc/apt/keyrings/sagernet.asc] <https://deb.sagernet.org/> * *" | \\
  sudo tee /etc/apt/sources.list.d/sagernet.list > /dev/null
sudo apt-get update
sudo apt-get install sing-box # or sing-box-beta
 
hostname
echo "PLS setting IP!!!"
read
 
tailscale_ip=$(tailscale ip --4)
 
# 检查 tailscale ip 命令是否成功执行
if [[ -z "$tailscale_ip" ]]; then
  echo "警告: 无法获取 Tailscale IP 地址!!!!!!!!"
  tailscale_ip="xxxxxxxxxxxx"
fi
 
# 构建 JSON 字符串,然后写入文件
printf '{
  "log": {
    "level": "info"
  },
  "inbounds": [
    {
      "type": "socks",
      "tag": "socks-in",
      "listen": "%s",
      "listen_port": 7690
    }
  ]
}' "$tailscale_ip" | sudo tee /etc/sing-box/config.json
 
# 检查写入是否成功
if [[ $? -eq 0 ]]; then
  echo "配置文件已成功写入 /etc/sing-box/config.json"
else
  echo "错误: 写入配置文件失败"
fi
 
sudo systemctl enable sing-box && sudo systemctl restart sing-box.service
# 让 gemini 写的

在主服务器上起 9 个 Zeno,绑到这 9 个 socks 上。最终花费一天的时间搞定,仅花费1欧元。

中间被 Gcore 的防火墙坑了,它那防火墙甚至能影响绑定在 tailscale interface 里的 socks 出站,导致 socks 无法将外网的 http response 发回 tailscale 另一端的 socks client,会 conn reset,非常神奇。

https://archive.org/search?query=title:%22Nico%20Nico%20Shunga%20-%20Original%20Images%22

(一开始在单机跑,所以 IA 上有 10 个 item)

详情页是关站前一天爬的,中途 OOM 了一次,如果 Zeno 的手搓 WAL 没出问题的话,应该也许大概没丢数据。

SHUNGA-WORK-DETAILS-crawling

niconico/shunga.txt · 最后更改: 2025/02/04 17:37 由 yzqzss

除额外注明的地方外,本维基上的内容按下列许可协议发布: CC0 1.0 Universal
CC0 1.0 Universal Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki