filter.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package crawler
  2. import (
  3. "net/url"
  4. "regexp"
  5. "strings"
  6. )
  7. // FilterResult URL 过滤结果
  8. type FilterResult int
  9. const (
  10. FilterDiscard FilterResult = iota // 直接丢弃
  11. FilterValid // 确定是导航站
  12. FilterUncertain // 不确定,需 LLM 判断
  13. )
  14. // 黑名单域名
  15. var blacklistDomains = []string{
  16. "t.me", "telegram.me", "twitter.com", "x.com", "facebook.com",
  17. "instagram.com", "youtube.com", "google.com", "baidu.com",
  18. "weibo.com", "zhihu.com", "github.com", "stackoverflow.com",
  19. "wikipedia.org", "amazon.com", "taobao.com", "jd.com", "tmall.com",
  20. "qq.com", "163.com", "126.com", "sina.com.cn", "sohu.com",
  21. "tencent.com", "alipay.com", "wechat.com", "apple.com",
  22. "microsoft.com", "windows.com", "android.com",
  23. }
  24. // 黑名单扩展名
  25. var blacklistExtensions = []string{
  26. ".apk", ".zip", ".pdf", ".exe", ".dmg", ".ipa", ".rar", ".7z",
  27. ".mp4", ".mp3", ".avi", ".jpg", ".png", ".gif", ".svg",
  28. ".css", ".js", ".json", ".xml",
  29. }
  30. // 黑名单路径片段
  31. var blacklistPaths = []string{
  32. "/api/", "/login/", "/logout/", "/register/", "/signup/",
  33. "/wp-admin/", "/admin/", "?ref=", "?utm_", "/cdn-cgi/",
  34. }
  35. // 正向信号
  36. var navSignals = []string{
  37. "nav", "directory", "catalog", "daohang", "dh", "list",
  38. "导航", "目录", "聚合", "推荐", "收录",
  39. }
  40. // RuleFilter 规则引擎过滤
  41. func RuleFilter(rawURL string) FilterResult {
  42. u, err := url.Parse(rawURL)
  43. if err != nil {
  44. return FilterDiscard
  45. }
  46. host := strings.ToLower(u.Hostname())
  47. path := strings.ToLower(u.Path)
  48. fullURL := strings.ToLower(rawURL)
  49. // 黑名单域名
  50. for _, d := range blacklistDomains {
  51. if strings.Contains(host, d) {
  52. return FilterDiscard
  53. }
  54. }
  55. // 黑名单扩展名
  56. for _, ext := range blacklistExtensions {
  57. if strings.HasSuffix(path, ext) {
  58. return FilterDiscard
  59. }
  60. }
  61. // 黑名单路径
  62. for _, p := range blacklistPaths {
  63. if strings.Contains(fullURL, p) {
  64. return FilterDiscard
  65. }
  66. }
  67. // 正向信号
  68. for _, sig := range navSignals {
  69. if strings.Contains(fullURL, sig) {
  70. return FilterValid
  71. }
  72. }
  73. return FilterUncertain
  74. }
  75. // ExtractDomain 提取域名
  76. func ExtractDomain(rawURL string) string {
  77. u, err := url.Parse(rawURL)
  78. if err != nil {
  79. return ""
  80. }
  81. return u.Hostname()
  82. }
  83. var reTGUsernameFromURL = regexp.MustCompile(`t(?:elegram)?\.me/([a-zA-Z][a-zA-Z0-9_]{4,31})`)
  84. // ExtractTGUsername 从 URL 提取 TG 用户名
  85. func ExtractTGUsername(rawURL string) string {
  86. m := reTGUsernameFromURL.FindStringSubmatch(rawURL)
  87. if len(m) > 1 {
  88. return m[1]
  89. }
  90. return ""
  91. }