{{tag>saved closed}}
^ ニコニコ春画 ^^
| URL | https://seiga.nicovideo.jp/shunga/ |
| 成立于 | 2011-8 |
| 关闭于 | 2025-1-29 |
| 别名 | NicoNico Shunga |
| 拥有者 | DWANGO Co., Ltd. |
| 数据量 | ~140GiB |
| project code | [[github>saveweb/niconico_shunga]] |
====== ニコニコ春画 ======
ニコニコ春画(NicoNico Shunga)是 ニコニコ静画(NicoNico Seiga)中的 R-15 分类,于 2025-1-29 14:00 (UTC+9) 删除((https://blog.nicovideo.jp/niconews/239363.html))。
> Q.「ニコニコ春画」とはなんですか?
> A.
> ニコニコ静画のイラストコーナー内にあるサービスです。「ニコニコ春画」では、投稿時にR-15カテゴリが設定されたイラストや、過度に性的・過激な表現が含まれると判断されたイラストが掲載されます。 ((https://blog.nicovideo.jp/niconews/239363.html))
另见:[[atwiki>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 来显示原图的。
把页面 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
}
})
+ //
+ 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,先把缩略图存了。
[[IA>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 >> .ssh/authorized_keys
curl -fsSL | sh && sudo tailscale up --auth-key=xxxxxxxx
sudo curl -fsSL -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] * *" | \\
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 没出问题的话,应该也许大概没丢数据。
[[IA>SHUNGA-WORK-DETAILS-crawling]]