Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] 疯狂刷新触发风控导致无法正常进行下载 #46

Open
sweetnotice opened this issue Apr 27, 2024 · 17 comments
Open

[BUG] 疯狂刷新触发风控导致无法正常进行下载 #46

sweetnotice opened this issue Apr 27, 2024 · 17 comments
Assignees
Labels
Already Reproduced 已经被复现 bug Something isn't working help wanted Extra attention is needed 拉锯战 跟随网站变化而改变爬虫策略

Comments

@sweetnotice
Copy link

Describe the bug(描述这个BUG)
选择章节进行下载后,浏览器会疯狂刷新,然后触发风控。浏览器以及驱动已确定为最新版 124.0.6367.91

To Reproduce(复现步骤)

from linovelib2epub import Linovelib2Epub

if __name__ == '__main__':
    # /path/to/chromedriver
    browser_driver_path = r'C:\Users\Administrator\Desktop\chromedriver-win64\chromedriver.exe'
    linovelib_epub = Linovelib2Epub(book_id=8, chapter_crawl_delay=3, page_crawl_delay=2, select_volume_mode=True,
                                    browser_driver_path=browser_driver_path,
                                    log_level='DEBUG')
    linovelib_epub.run()

Screenshots or Video(截图或者视频录制)
image

Environment(软件环境)

  • OS Verison: 例如:Windows 10 专业版22h2
  • Python Version: Python 3.10.9
  • Pip Version: pip --version

Additional context(补充信息[可选])
Add any other context about the problem here.
www.bilinovel.com_8.log

@sweetnotice sweetnotice added the bug Something isn't working label Apr 27, 2024
@sweetnotice sweetnotice changed the title [BUG] 无法正常进行下载 [BUG] 疯狂刷新触发风控导致无法正常进行下载 Apr 27, 2024
@wdpm
Copy link
Member

wdpm commented Apr 27, 2024

文档中已经对此进行了说明,这是一个已知的缺陷。
image
image

由于 selenium 的浏览器特征指纹太老,在2024年来看,已经是强弩之末了。
后续我可能会将其改为目前较为隐蔽的 DrissionPage 库。
目前来说,你只能更换你的网络环境,或者碰运气等它不检测你。

@sweetnotice
Copy link
Author

感谢回答。请问您有什么好办法可以还原每话最后的那一段js后加载的字库混淆文字吗。js混淆强度好高,让我这个不怎么了解js的小白望而却步了

@wdpm
Copy link
Member

wdpm commented Apr 27, 2024

感谢回答。请问您有什么好办法可以还原每话最后的那一段js后加载的字库混淆文字吗。js混淆强度好高,让我这个不怎么了解js的小白望而却步了

具体描述下你的问题细节(例如哪个文件,进行到哪一步,卡在哪),你这样问我不清楚你的疑惑点。

@sweetnotice
Copy link
Author

额,不是关于软件的问题,而是网站逆向方面的一些问题,现在哔哩轻小说又更新加密了。每话最后的一段文本不使用以前的js 正则替换 而改为使用字库进行替换,我也做过尝试,但还是解决不了,所以请教大佬给点思路
image

@wdpm
Copy link
Member

wdpm commented Apr 27, 2024

给你上面这个截图的文章页链接地址给我,我去看下。

@sweetnotice
Copy link
Author

给你上面这个截图的文章页链接地址给我,我去看下。

pc端
移动端
据我所知这个加密已经上线有一段时间了,pc端一个礼拜左右,移动端是最近上线的。
能很明显的看到最后一段话字体与别的文字不一样

@wdpm
Copy link
Member

wdpm commented Apr 27, 2024

爬虫 —— CSS 字体混淆

image

.bcontent p:last-of-type {
    /* font-family: "read" !important; */
}

可以得知它是使用了字体进行覆盖。这个特殊字体的样式应用后,就能拿到正常的文本了。
没有应用这个字体时,拿到的是混淆乱码。这个做法是为了坑一下直接API请求爬虫。例如 python requests这类。

@font-face {
    font-family: read;
    font-display: block;
    src: url('/public/font/read.woff2') format('woff2'), url('/public/font/read.ttf') format('truetype');
}

追踪这个字体
image

也就是它使用这个自己定义的字体。

具体代码解决思路

TODO

@wdpm
Copy link
Member

wdpm commented Apr 27, 2024

寄,目前 linovelib 应该设置了IP黑名单机制了。我在本地也没法测试我的解决方案。显示的是被服务器ban了。
估计要尽快将selenium切换到 DrissionPage,快进到自研爬虫浏览器指纹。(bushi)

@wdpm wdpm self-assigned this Apr 27, 2024
@wdpm wdpm added Already Reproduced 已经被复现 help wanted Extra attention is needed 拉锯战 跟随网站变化而改变爬虫策略 labels Apr 27, 2024
@sweetnotice
Copy link
Author

寄,目前 linovelib 应该设置了IP黑名单机制了。我在本地也没法测试我的解决方案。 估计要尽快将selenium切换到 DrissionPage,快进到自研爬虫浏览器指纹。(bushi)

祝大佬武运昌盛。另外我觉得可以不依赖浏览器的,可以纯get请求再加js逆向,这样运行可以更稳。佬可以看看我的仓库。
Bilinoval_DL之前都是可以稳定运行的,就是因为最近加了个这个东西,我只会简单的js逆向,没学过js。。。

@wdpm
Copy link
Member

wdpm commented Apr 27, 2024

@sweetnotice 这个项目以前就是使用 requests这种的,后来被迫改为无头浏览器。
因为拦截点太多了,例如:

  • cloudflare 过风控检测
  • CSS渲染,或者补JS环境来复原混淆
  • 可能以后还会出现各种奇奇怪怪的验证码
  • ...

纯API请求我认为是一条绝路,因为linovelib这类网站只会更加严控爬虫。
我暂时没时间来探索其他的仓库,这个项目的维护其实也不是很活跃。

@sweetnotice
Copy link
Author

sweetnotice commented Apr 27, 2024

确实。DrissionPage其实也挺完美的

  • 能过cloudflare
  • 能抓包
  • 所见即所得
  • 以前麻烦的点是得自己装Chromedriver,现在也解决了
  • 最重要的是比逆向那些恶心的js例如瑞数花的时间成本低

除了在内存低的机器上不太好运行,不方便调试外几乎没有缺点了。
哔哩轻小说什么时候才能开放注册啊,等了快半年了,实在没办法才做的爬虫,它有功夫做反爬不如给他那个注册开开。哎

@wdpm
Copy link
Member

wdpm commented May 7, 2024

@sweetnotice 这个问题已被间接修复。
目前 mobile 版本即手机版本的linovelib,我也没法突破cloudflare。因此我改为爬取它的PC版本即电脑版本。
关于字体混淆的研究与解决方案,我记录在了这个md文件中,如果你感兴趣,可以查看 linovelib-pc-font-obfuscation

关于最新版本代码,请更新项目源码并仔细阅读README文档来运行。

@sweetnotice
Copy link
Author

sweetnotice commented May 7, 2024

牛啊老哥.
使用ocr的方式确实是修上了,它那个字库字太多了,用ocr做字体映射也麻烦.直接ocr网页确实是一个聪明的想法.
我有几个建议:

  • 也许可以让用户自行选择设置ocr接口 例如 '百度ocr' 什么的,获得更精确的识别体验
  • 可以将 DrissionPage 的page设置为 eager模式 参考官网文档 DrissionPage 加载模式 用来只加载页面文字以减轻网络负担,加快请求速度

@wdpm
Copy link
Member

wdpm commented May 8, 2024

也许可以让用户自行选择设置ocr接口 例如 '百度ocr' 什么的,获得更精确的识别体验

目前只有少部分章节的某些页面的最后一个段落p存在CSS 字体混淆,我认为混淆面积比例不大,而且pytesseract的识别率对于简体/繁体/english的识别准确率并不低。因此在目前阶段我不会考虑增强OCR。

可以将 DrissionPage 的page设置为 eager模式 参考官网文档 DrissionPage 加载模式 用来只加载页面文字以减轻网络负担,加快请求速度

你的想法是很好的,可是事实上却不能这样做。因为仅加载页面文字是不足够的,必须完全加载整个页面,同时必须渲染CSS样式,以及执行关于JS恢复混淆的相关逻辑。

  • 渲染CSS样式*:程序中需要获取相关活跃的CSS样式表,来判断当前页面是否存在字体混淆。
  • JS恢复混淆:这是pctheme.js中的一个逻辑,网页源码是根据混淆表(一个dict)混淆后的,JS会把他们复原。

image
上面是一个关于浏览器解析执行流程的示意图。JS执行部分目测是在DOMContentLoaded之前,这没问题。
关键的问题是这个CSS渲染的时机似乎和DOMContentLoaded独立,因此不好把控。

因此,CSS样式渲染和JS执行缺一不可,所以我目前认为eager模式不适用。
@sweetnotice

@sweetnotice
Copy link
Author

经过我本地测试,eager模式是可以正常工作的,可以正常显示需要用js复原的字体,这是我简化后不完全代码

# 这是您给出的js代码
js_check = """
const last_p = document.querySelector('#TextContent p:last-of-type')
const p_style = window.getComputedStyle(last_p)
const p_font_style = p_style.getPropertyValue('font-family')
if (p_font_style && p_font_style.includes('read')) {
    return true;
}
return false;
"""

def dp_get_chapter_text(chapter_url):
    page = ChromiumPage()
    page.set.load_mode.eager()  # 设置为eager模式 加载完 DOM 或超时即停止加载,不加载页面资源
    page.get(chapter_url, timeout=5, retry=2)

    texts = ''
    text = page.ele('x://*[@id="TextContent"]').html  # 获取章节文本
    text = re.sub('<div class="google-auto-placed.*?</ins></div>', '', text)  # 去除谷歌广告
    text = re.sub('<ins class="adsbygoogle".*?</ins>', '', text)
    texts += text
    if page.run_js(js_check):
        last_p = page.ele('css:#TextContent p:last-of-type')
        base64_pic = last_p.get_screenshot(as_base64='png')  # 返回截图二进制文本
        ocr_word = ocr_api.high_precision_ocr(base64_pic) # 使用百度ocr识别
        texts = texts.replace(last_p.text, ocr_word)

@wdpm
Copy link
Member

wdpm commented May 9, 2024

经过简单的本地测试,eager 模式的确可行,性能提升为一个页面从平均1s到0.3s,提升幅度为 0.7s/1.0s *100=70%。
@all-contributors add @sweetnotice as a contributor for bug.

Copy link
Contributor

@wdpm

I've put up a pull request to add @sweetnotice! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Already Reproduced 已经被复现 bug Something isn't working help wanted Extra attention is needed 拉锯战 跟随网站变化而改变爬虫策略
Projects
None yet
Development

No branches or pull requests

2 participants