用户工具

站点工具


niconico:shunga

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
niconico:shunga [2025/02/04 17:33] – 移除 - 外部编辑 (未知日期) 127.0.0.1niconico:shunga [2025/02/04 17:37] (当前版本) yzqzss
行 1: 行 1:
 +{{tag>saved closed}}
  
 +<WRAP right>
 +^  ニコニコ春画  ^^
 +| URL    | https://seiga.nicovideo.jp/shunga/ |
 +| 成立于  | 2011-8 |
 +| 关闭于  | 2025-1-29 |
 +| 别名    | NicoNico Shunga |
 +| 拥有者  | DWANGO Co., Ltd. |
 +| 数据量  | ~140GiB |
 +| project code | [[github>saveweb/niconico_shunga]] |
 +</WRAP>
 +
 +====== ニコニコ春画 ======
 +
 +ニコニコ春画(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 来显示原图的。
 +
 +<code html5>
 +<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>
 +</code>
 +
 +把页面 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,忽略了用户指定的路径。懒得修了)。
 +
 +<code diff>
 +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
 +</code>
 +
 +Zeno v1 的通用外链提取器没有覆盖到 div:data-src 和 div:data-watch_url 。
 +
 +<code diff>
 +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) {
 +</code>
 +
 +对 /priv/ 的图链做全局限速。
 +
 +<code diff>
 +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 {
 +</code>
 +
 +===== 存档过程 =====
 +
 +遍历得到大概 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 代理。
 +
 +<code bash>
 +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 写的
 +</code>
 +
 +在主服务器上起 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]]

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