rodHelper.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package rod_helper
  2. import (
  3. "context"
  4. _ "embed"
  5. "errors"
  6. "github.com/allanpk716/ChineseSubFinder/internal/pkg"
  7. "github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
  8. "github.com/allanpk716/ChineseSubFinder/internal/pkg/random_useragent"
  9. "github.com/go-rod/rod"
  10. "github.com/go-rod/rod/lib/launcher"
  11. "github.com/go-rod/rod/lib/proto"
  12. "github.com/mholt/archiver/v3"
  13. "os"
  14. "path"
  15. "path/filepath"
  16. "sync"
  17. "time"
  18. )
  19. /**
  20. * @Description: 新建一个支持代理的 browser 对象,使用完毕后,需要删除 adblockFilePath 文件夹
  21. * @param httpProxyURL http://127.0.0.1:10809
  22. * @return *rod.Browser
  23. * @return error
  24. */
  25. func NewBrowser(httpProxyURL string, loadAdblock bool) (*rod.Browser, error) {
  26. var err error
  27. once.Do(func() {
  28. adblockSavePath, err = releaseAdblock()
  29. if err != nil {
  30. log_helper.GetLogger().Errorln("releaseAdblock", err)
  31. }
  32. })
  33. var browser *rod.Browser
  34. err = rod.Try(func() {
  35. purl := ""
  36. if loadAdblock == true {
  37. purl = launcher.New().
  38. Delete("disable-extensions").
  39. Set("load-extension", adblockSavePath).
  40. Proxy(httpProxyURL).
  41. Headless(false). // 插件模式需要设置这个
  42. //XVFB("--server-num=5", "--server-args=-screen 0 1600x900x16").
  43. //XVFB("-ac :99", "-screen 0 1280x1024x16").
  44. MustLaunch()
  45. } else {
  46. purl = launcher.New().
  47. Proxy(httpProxyURL).
  48. MustLaunch()
  49. }
  50. browser = rod.New().ControlURL(purl).MustConnect()
  51. })
  52. if err != nil {
  53. return nil, err
  54. }
  55. return browser, nil
  56. }
  57. /**
  58. * @Description: 访问目标 Url,返回 page,只是这个 page 有效,如果再次出发其他的事件无效
  59. * @param desURL 目标 Url
  60. * @param httpProxyURL http://127.0.0.1:10809
  61. * @param timeOut 超时时间
  62. * @param maxRetryTimes 当是非超时 err 的时候,最多可以重试几次
  63. * @return *rod.Page
  64. * @return error
  65. */
  66. func NewBrowserFromDocker(httpProxyURL, remoteDockerURL string) (*rod.Browser, error) {
  67. var browser *rod.Browser
  68. err := rod.Try(func() {
  69. l := launcher.MustNewManaged(remoteDockerURL)
  70. u := l.Proxy(httpProxyURL).MustLaunch()
  71. l.Headless(false).XVFB()
  72. browser = rod.New().Client(l.Client()).ControlURL(u).MustConnect()
  73. })
  74. if err != nil {
  75. return nil, err
  76. }
  77. return browser, nil
  78. }
  79. func NewPageNavigate(browser *rod.Browser, desURL string, timeOut time.Duration, maxRetryTimes int) (*rod.Page, error) {
  80. page, err := newPage(browser)
  81. if err != nil {
  82. return nil, err
  83. }
  84. page.MustSetUserAgent(&proto.NetworkSetUserAgentOverride{
  85. UserAgent: random_useragent.RandomUserAgent(true),
  86. })
  87. page = page.Timeout(timeOut)
  88. nowRetryTimes := 0
  89. for nowRetryTimes <= maxRetryTimes {
  90. err = rod.Try(func() {
  91. page.MustNavigate(desURL).MustWaitLoad()
  92. nowRetryTimes++
  93. })
  94. if errors.Is(err, context.DeadlineExceeded) {
  95. // 超时
  96. return nil, err
  97. } else if err == nil {
  98. // 没有问题
  99. return page, nil
  100. }
  101. }
  102. return nil, err
  103. }
  104. // ReloadBrowser 提前把浏览器下载好
  105. func ReloadBrowser() {
  106. newBrowser, err := NewBrowser("", true)
  107. defer func() {
  108. _ = newBrowser.Close()
  109. }()
  110. if err != nil {
  111. return
  112. }
  113. page, err := NewPageNavigate(newBrowser, "https://www.baidu.com", 30*time.Second, 5)
  114. if err != nil {
  115. return
  116. }
  117. defer func() {
  118. _ = page.Close()
  119. }()
  120. }
  121. // Clear 清理缓存
  122. func Clear() {
  123. l := launcher.New().
  124. Headless(false).
  125. Devtools(true)
  126. defer l.Cleanup() // remove launcher.FlagUserDataDir
  127. url := l.MustLaunch()
  128. // Trace shows verbose debug information for each action executed
  129. // Slowmotion is a debug related function that waits 2 seconds between
  130. // each action, making it easier to inspect what your code is doing.
  131. browser := rod.New().
  132. ControlURL(url).
  133. Trace(true).
  134. SlowMotion(2 * time.Second).
  135. MustConnect()
  136. defer browser.MustClose()
  137. }
  138. func newPage(browser *rod.Browser) (*rod.Page, error) {
  139. page, err := browser.Page(proto.TargetCreateTarget{URL: ""})
  140. if err != nil {
  141. return nil, err
  142. }
  143. return page, err
  144. }
  145. // releaseAdblock 从程序中释放 adblock 插件出来到本地路径
  146. func releaseAdblock() (string, error) {
  147. adblockFolderPath := filepath.Join(os.TempDir(), "chinesesubfinder")
  148. err := os.MkdirAll(path.Join(adblockFolderPath), os.ModePerm)
  149. if err != nil {
  150. return "", err
  151. }
  152. desPath := path.Join(adblockFolderPath, "RunAdblock")
  153. // 清理之前缓存的信息
  154. _ = pkg.ClearFolder(desPath)
  155. // 具体把 adblock zip 解压下载到哪里
  156. outZipFileFPath := path.Join(adblockFolderPath, "adblock.zip")
  157. adblockZipFile, err := os.Create(outZipFileFPath)
  158. if err != nil {
  159. return "", err
  160. }
  161. defer func() {
  162. _ = adblockZipFile.Close()
  163. _ = os.Remove(outZipFileFPath)
  164. }()
  165. _, err = adblockZipFile.Write(adblockFolder)
  166. if err != nil {
  167. return "", err
  168. }
  169. r := archiver.NewZip()
  170. err = r.Unarchive(outZipFileFPath, desPath)
  171. if err != nil {
  172. return "", err
  173. }
  174. return path.Join(desPath, adblockInsideName), err
  175. }
  176. const adblockInsideName = "adblock"
  177. var once sync.Once
  178. // 这个文件内有一个子文件夹 adblock ,制作的时候务必注意
  179. //go:embed assets/adblock_v4.34.0.zip
  180. var adblockFolder []byte
  181. var adblockSavePath string