{{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]]