上传文件至 backend/cmd
This commit is contained in:
620
backend/cmd/main.go
Normal file
620
backend/cmd/main.go
Normal file
@@ -0,0 +1,620 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/wechat-crawler/configs"
|
||||
"github.com/wechat-crawler/pkg/utils"
|
||||
"github.com/wechat-crawler/pkg/wechat"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("微信公众号文章爬取工具 v1.0")
|
||||
fmt.Println("==============================")
|
||||
|
||||
// 初始化配置
|
||||
cfg := configs.NewConfig()
|
||||
|
||||
// 检查命令行参数
|
||||
if len(os.Args) > 1 && os.Args[1] != "" {
|
||||
// 如果提供了文章链接参数,使用新的方法
|
||||
articleLink := os.Args[1]
|
||||
fmt.Printf("\n从文章链接开始操作: %s\n", articleLink)
|
||||
|
||||
// 直接获取公众号主页链接,不依赖cookie,不进行后续爬取
|
||||
officialAccountLink, err := GetOfficialAccountLinkFromArticleOnly(articleLink)
|
||||
if err != nil {
|
||||
log.Fatalf("获取公众号主页链接失败: %v", err)
|
||||
}
|
||||
fmt.Printf("公众号主页链接: %s\n", officialAccountLink)
|
||||
return
|
||||
}
|
||||
|
||||
// 显示功能菜单
|
||||
showMenu(cfg)
|
||||
|
||||
fmt.Println("\n操作完成!")
|
||||
}
|
||||
|
||||
func startCrawling(cfg *configs.Config) {
|
||||
// 读取cookie信息
|
||||
cookiePath := filepath.Join(cfg.RootPath, "cookie.txt")
|
||||
cookieContent, err := ioutil.ReadFile(cookiePath)
|
||||
if err != nil {
|
||||
fmt.Printf("读取cookie失败: %v,请确保cookie.txt文件存在\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 解析cookie获取必要参数
|
||||
cookieStr := string(cookieContent)
|
||||
biz, uin, key, passTicket, err := parseCookieInfo(cookieStr)
|
||||
if err != nil {
|
||||
fmt.Printf("解析cookie信息失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建爬虫实例
|
||||
crawler, err := wechat.NewWechatCrawler(biz, uin, key, passTicket, cfg)
|
||||
if err != nil {
|
||||
fmt.Printf("创建爬虫实例失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取公众号名称
|
||||
nickname, err := crawler.GetOfficialAccountName()
|
||||
if err != nil {
|
||||
fmt.Printf("获取公众号名称失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("\n正在爬取公众号: %s\n", nickname)
|
||||
|
||||
// 创建公众号目录
|
||||
officialPath := filepath.Join(cfg.RootPath, "data", nickname)
|
||||
err = utils.CreateDir(officialPath)
|
||||
if err != nil {
|
||||
fmt.Printf("创建目录失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取所有文章列表
|
||||
fmt.Println("\n开始获取文章列表...")
|
||||
articleList := [][]string{}
|
||||
page := 0
|
||||
for {
|
||||
fmt.Printf("正在获取第 %d 页文章...\n", page+1)
|
||||
result, err := crawler.GetNextList(page)
|
||||
if err != nil {
|
||||
fmt.Printf("获取第 %d 页文章失败: %v\n", page+1, err)
|
||||
break
|
||||
}
|
||||
|
||||
if result["m_flag"].(int) == 0 {
|
||||
fmt.Printf("已获取全部文章,共 %d 页\n", page)
|
||||
break
|
||||
}
|
||||
|
||||
passageList := result["passage_list"].([][]string)
|
||||
articleList = append(articleList, passageList...)
|
||||
|
||||
fmt.Printf("第 %d 页获取成功,新增 %d 篇文章\n", page+1, len(passageList))
|
||||
|
||||
page++
|
||||
// 防止请求过于频繁
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
fmt.Printf("\n共获取到 %d 篇文章\n", len(articleList))
|
||||
|
||||
// 保存文章列表
|
||||
err = crawler.SaveArticleListToExcel(officialPath, articleList, nickname)
|
||||
if err != nil {
|
||||
fmt.Printf("保存文章列表失败: %v\n", err)
|
||||
}
|
||||
|
||||
// 转换文章链接(这个方法不需要单独调用,GetArticleList已经内部调用了)
|
||||
// 文章列表已经在GetArticleList方法中转换过了
|
||||
|
||||
// 读取文章链接
|
||||
links, err := crawler.ReadArticleLinksFromExcel(filepath.Join(officialPath, "文章列表(article_list)_原始链接.txt"))
|
||||
if err != nil {
|
||||
// 如果读取失败,直接使用articleList中的链接
|
||||
links = []string{}
|
||||
for _, article := range articleList {
|
||||
links = append(links, article[3])
|
||||
}
|
||||
}
|
||||
|
||||
// 获取文章详情
|
||||
fmt.Println("\n开始获取文章详情...")
|
||||
for i, link := range links {
|
||||
fmt.Printf("正在获取文章 %d/%d: %s\n", i+1, len(links), link)
|
||||
|
||||
// 转换链接
|
||||
transformedLink := utils.TransformLink(link)
|
||||
|
||||
// 获取文章内容
|
||||
content, err := crawler.GetOneArticle(transformedLink)
|
||||
if err != nil {
|
||||
fmt.Printf("获取文章内容失败: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 提取文章标题
|
||||
title := ""
|
||||
for _, article := range articleList {
|
||||
if article[3] == link {
|
||||
title = article[2]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 提取创建时间
|
||||
createTime := ""
|
||||
for _, article := range articleList {
|
||||
if article[3] == link {
|
||||
createTime = article[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 提取评论ID
|
||||
commentID, _ := utils.ExtractFromRegex(content, "comment_id = '(.*?)';")
|
||||
|
||||
// 生成req_id
|
||||
reqID := fmt.Sprintf("%d", time.Now().UnixNano())
|
||||
|
||||
// 获取文章统计信息
|
||||
stats, err := crawler.GetArticleStats(link, title, commentID, reqID, createTime)
|
||||
if err != nil {
|
||||
fmt.Printf("获取文章统计信息失败: %v\n", err)
|
||||
// 设置默认值
|
||||
stats = map[string]string{
|
||||
"read_num": "0",
|
||||
"old_like_num": "0",
|
||||
"share_num": "0",
|
||||
"show_read": "0",
|
||||
}
|
||||
}
|
||||
|
||||
// 获取文章评论
|
||||
comments, commentLikes, err := crawler.GetArticleComments(commentID)
|
||||
if err != nil {
|
||||
fmt.Printf("获取文章评论失败: %v\n", err)
|
||||
comments = []string{}
|
||||
commentLikes = []string{}
|
||||
}
|
||||
|
||||
// 解析文章正文内容(这里简化处理,实际需要使用goquery进行HTML解析)
|
||||
articleContent := parseArticleContent(content)
|
||||
|
||||
// 创建文章详情对象
|
||||
detail := &wechat.ArticleDetail{
|
||||
LocalTime: utils.GetCurrentTime(),
|
||||
CreateTime: createTime,
|
||||
Title: title,
|
||||
Link: transformedLink,
|
||||
Content: articleContent,
|
||||
ReadCount: stats["read_num"],
|
||||
LikeCount: stats["old_like_num"],
|
||||
ShareCount: stats["share_num"],
|
||||
ShowRead: stats["show_read"],
|
||||
Comments: comments,
|
||||
CommentLikes: commentLikes,
|
||||
CommentID: commentID,
|
||||
}
|
||||
|
||||
// 保存文章详情
|
||||
err = crawler.SaveArticleDetailToExcel(detail, officialPath)
|
||||
if err != nil {
|
||||
fmt.Printf("保存文章详情失败: %v\n", err)
|
||||
}
|
||||
|
||||
// 防止请求过于频繁
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
|
||||
fmt.Printf("\n公众号 %s 爬取完成!\n", nickname)
|
||||
}
|
||||
|
||||
func parseCookieInfo(cookieStr string) (string, string, string, string, error) {
|
||||
// 从cookie中提取必要的参数
|
||||
biz, err := utils.ExtractFromRegex(cookieStr, "__biz=(.*?);")
|
||||
if err != nil {
|
||||
return "", "", "", "", fmt.Errorf("未找到__biz参数")
|
||||
}
|
||||
|
||||
uin, err := utils.ExtractFromRegex(cookieStr, "uin=(.*?);")
|
||||
if err != nil {
|
||||
return "", "", "", "", fmt.Errorf("未找到uin参数")
|
||||
}
|
||||
|
||||
key, err := utils.ExtractFromRegex(cookieStr, "key=(.*?);")
|
||||
if err != nil {
|
||||
return "", "", "", "", fmt.Errorf("未找到key参数")
|
||||
}
|
||||
|
||||
passTicket, err := utils.ExtractFromRegex(cookieStr, "pass_ticket=(.*?);")
|
||||
if err != nil {
|
||||
return "", "", "", "", fmt.Errorf("未找到pass_ticket参数")
|
||||
}
|
||||
|
||||
return biz, uin, key, passTicket, nil
|
||||
}
|
||||
|
||||
func parseArticleContent(content string) []string {
|
||||
// 这里简化处理,实际需要使用goquery进行HTML解析
|
||||
// 提取文章正文内容
|
||||
var result []string
|
||||
|
||||
// 尝试提取body内容
|
||||
bodyContent, err := utils.ExtractFromRegex(content, "<body[^>]*>(.*?)</body>")
|
||||
if err != nil {
|
||||
result = append(result, "无法解析文章内容")
|
||||
return result
|
||||
}
|
||||
|
||||
// 简单去除HTML标签
|
||||
txt := strings.ReplaceAll(bodyContent, "<", " <")
|
||||
txt = strings.ReplaceAll(txt, ">", "> ")
|
||||
|
||||
// 按行分割并过滤空白行
|
||||
lines := strings.Split(txt, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line != "" && !strings.HasPrefix(line, "<") {
|
||||
result = append(result, line)
|
||||
// 限制内容长度
|
||||
if len(result) > 100 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 仅从文章链接获取公众号主页链接,不依赖cookie,不进行后续爬取
|
||||
func GetOfficialAccountLinkFromArticleOnly(articleLink string) (string, error) {
|
||||
// 创建一个简单的爬虫实例,不需要cookie信息
|
||||
crawler := wechat.NewSimpleCrawler()
|
||||
|
||||
// 从文章链接获取公众号主页链接
|
||||
officialAccountLink, err := crawler.GetOfficialAccountLinkFromArticle(articleLink)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("获取文章内容失败: %v", err)
|
||||
}
|
||||
|
||||
return officialAccountLink, nil
|
||||
}
|
||||
|
||||
// 从文章链接开始爬取
|
||||
func startCrawlingFromArticleLink(cfg *configs.Config, articleLink string) {
|
||||
// 读取cookie信息
|
||||
cookiePath := filepath.Join(cfg.RootPath, "cookie.txt")
|
||||
cookieContent, err := ioutil.ReadFile(cookiePath)
|
||||
if err != nil {
|
||||
fmt.Printf("读取cookie失败: %v,请确保cookie.txt文件存在\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 解析cookie获取必要参数
|
||||
cookieStr := string(cookieContent)
|
||||
_, uin, key, passTicket, err := parseCookieInfo(cookieStr)
|
||||
if err != nil {
|
||||
fmt.Printf("解析cookie信息失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建爬虫实例(biz将通过文章链接获取)
|
||||
crawler, err := wechat.NewWechatCrawler("", uin, key, passTicket, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("创建爬虫实例失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 1. 从文章链接获取公众号主页链接
|
||||
officialAccountLink, err := crawler.GetOfficialAccountLinkFromArticle(articleLink)
|
||||
if err != nil {
|
||||
log.Fatalf("获取公众号主页链接失败: %v", err)
|
||||
}
|
||||
fmt.Printf("获取到公众号主页链接: %s\n", officialAccountLink)
|
||||
|
||||
// 2. 获取公众号名称
|
||||
officialAccountName, err := crawler.GetOfficialAccountName()
|
||||
if err != nil {
|
||||
log.Printf("警告: 获取公众号名称失败: %v,将使用默认名称", err)
|
||||
officialAccountName = "公众号_" + time.Now().Format("20060102150405")
|
||||
}
|
||||
fmt.Printf("获取到公众号名称: %s\n", officialAccountName)
|
||||
|
||||
// 3. 创建输出目录
|
||||
outputDir := filepath.Join(cfg.RootPath, "data", officialAccountName)
|
||||
err = utils.CreateDir(outputDir)
|
||||
if err != nil {
|
||||
log.Fatalf("创建输出目录失败: %v", err)
|
||||
}
|
||||
|
||||
// 4. 获取文章列表(使用我们新实现的GetArticleList方法)
|
||||
fmt.Println("\n开始获取文章列表...")
|
||||
articleList, err := crawler.GetArticleList()
|
||||
if err != nil {
|
||||
log.Fatalf("获取文章列表失败: %v", err)
|
||||
}
|
||||
|
||||
// 5. 保存文章列表到Excel
|
||||
excelPath := filepath.Join(outputDir, "文章列表.xlsx")
|
||||
if err := crawler.SaveArticleListToExcel(outputDir, articleList, officialAccountName); err != nil {
|
||||
log.Fatalf("保存文章列表失败: %v", err)
|
||||
}
|
||||
fmt.Printf("文章列表已保存到: %s\n", excelPath)
|
||||
fmt.Printf("共获取到 %d 篇文章\n", len(articleList))
|
||||
|
||||
// 6. 获取文章详情(使用我们新实现的GetDetailList方法)
|
||||
fmt.Println("\n开始获取文章详情...")
|
||||
if err := crawler.GetDetailList(articleList, outputDir); err != nil {
|
||||
log.Fatalf("获取文章详情失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("\n公众号 %s 爬取完成!\n", officialAccountName)
|
||||
}
|
||||
|
||||
// 显示功能菜单
|
||||
func showMenu(cfg *configs.Config) {
|
||||
screenText := `请输入数字键!
|
||||
数字键1:仅获取公众号主页链接(输入公众号下任意一篇已发布的文章链接即可,无需cookie)
|
||||
数字键2:使用cookie信息爬取公众号文章
|
||||
数字键3:通过access_token和pages获取文章链接列表
|
||||
数字键4:根据先前生成的文章链接列表下载文件
|
||||
数字键5:根据公众号名称或链接,从文件读取文章列表并下载内容
|
||||
输入其他任意字符退出!`
|
||||
fmt.Println(screenText)
|
||||
|
||||
for {
|
||||
text := ""
|
||||
fmt.Print("请输入功能数字:")
|
||||
fmt.Scanln(&text)
|
||||
|
||||
if text == "1" {
|
||||
articleLink := ""
|
||||
fmt.Print("请输入公众号下任意一篇已发布的文章链接:")
|
||||
fmt.Scanln(&articleLink)
|
||||
if articleLink == "" {
|
||||
fmt.Println("链接不能为空,请重新输入")
|
||||
continue
|
||||
}
|
||||
|
||||
officialAccountLink, err := GetOfficialAccountLinkFromArticleOnly(articleLink)
|
||||
if err != nil {
|
||||
fmt.Printf("获取失败: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("\n成功获取公众号主页链接:\n%s\n", officialAccountLink)
|
||||
}
|
||||
fmt.Println("\n" + screenText)
|
||||
|
||||
} else if text == "2" {
|
||||
// 使用原有的方法
|
||||
fmt.Println("\n使用cookie中的信息爬取")
|
||||
startCrawling(cfg)
|
||||
break
|
||||
} else if text == "3" {
|
||||
// 通过access_token和pages获取文章链接列表
|
||||
fmt.Println("\n通过access_token和pages获取文章链接列表")
|
||||
startGettingArticleListByAccessToken(cfg)
|
||||
fmt.Println("\n" + screenText)
|
||||
} else if text == "4" {
|
||||
// 根据先前生成的文章链接列表下载文件
|
||||
fmt.Println("\n根据先前生成的文章链接列表下载文件")
|
||||
fmt.Println("功能4执行完成")
|
||||
fmt.Println("\n" + screenText)
|
||||
} else if text == "5" {
|
||||
// 根据公众号名称或链接,从文件读取文章列表并下载内容
|
||||
fmt.Println("\n开始执行:根据公众号名称或链接,从文件读取文章列表并下载内容")
|
||||
crawler, err := wechat.NewWechatCrawler("", "", "", "", cfg)
|
||||
if err != nil {
|
||||
fmt.Printf("创建爬虫实例失败: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 获取用户输入
|
||||
fmt.Print("请输入公众号名称或文章链接:")
|
||||
var nameLink string
|
||||
fmt.Scanln(&nameLink)
|
||||
|
||||
// 设置是否保存图片和内容
|
||||
imgSaveFlag := false
|
||||
contentSaveFlag := true
|
||||
|
||||
fmt.Print("是否保存图片?(y/n,默认n):")
|
||||
var imgChoice string
|
||||
fmt.Scanln(&imgChoice)
|
||||
if imgChoice == "y" || imgChoice == "Y" {
|
||||
imgSaveFlag = true
|
||||
}
|
||||
|
||||
// 执行功能
|
||||
err = crawler.GetListArticleFromFile(nameLink, imgSaveFlag, contentSaveFlag)
|
||||
if err != nil {
|
||||
fmt.Printf("功能执行失败: %v\n", err)
|
||||
} else {
|
||||
fmt.Println("功能5执行完成")
|
||||
}
|
||||
fmt.Println("\n" + screenText)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通过access_token和pages获取文章链接列表
|
||||
func startGettingArticleListByAccessToken(cfg *configs.Config) {
|
||||
// 提示用户输入从fiddler获取的链接
|
||||
fmt.Println("【accessToken获取方式提示】")
|
||||
fmt.Println("1. 使用Fiddler等抓包工具,设置代理监听浏览器流量")
|
||||
fmt.Println("2. 打开微信公众号文章列表页面,向下滚动加载更多文章")
|
||||
fmt.Println("3. 在Fiddler中找到包含\"list\"和\"access_token\"参数的请求")
|
||||
fmt.Println("4. 复制完整的请求URL作为输入")
|
||||
fmt.Println("5. 文章页数为想要获取的历史文章数量,通常每10篇文章为1页")
|
||||
fmt.Println()
|
||||
accessToken := ""
|
||||
fmt.Print("请输入从fiddler获取的链接(包含access_token等参数):")
|
||||
fmt.Scanln(&accessToken)
|
||||
if accessToken == "" {
|
||||
fmt.Println("链接不能为空,请重新输入")
|
||||
return
|
||||
}
|
||||
|
||||
// 提示用户输入文章页数
|
||||
pagesStr := ""
|
||||
fmt.Print("请输入要获取的文章页数(0表示全部):")
|
||||
fmt.Scanln(&pagesStr)
|
||||
|
||||
// 转换页数为整数
|
||||
pages := 0
|
||||
if pagesStr != "" {
|
||||
_, err := fmt.Sscanf(pagesStr, "%d", &pages)
|
||||
if err != nil || pages < 0 {
|
||||
fmt.Println("页数输入错误,将使用默认值0(全部)")
|
||||
pages = 0
|
||||
}
|
||||
}
|
||||
|
||||
// 从access_token中提取必要参数
|
||||
biz, uin, key, passTicket, err := parseAccessTokenParams(accessToken)
|
||||
if err != nil {
|
||||
fmt.Printf("解析access_token失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建爬虫实例
|
||||
crawler, err := wechat.NewWechatCrawler(biz, uin, key, passTicket, cfg)
|
||||
if err != nil {
|
||||
fmt.Printf("创建爬虫实例失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取公众号名称
|
||||
nickname, err := crawler.GetOfficialAccountName()
|
||||
if err != nil {
|
||||
fmt.Printf("获取公众号名称失败: %v,将使用默认名称\n", err)
|
||||
nickname = "公众号_" + time.Now().Format("20060102150405")
|
||||
}
|
||||
|
||||
fmt.Printf("\n正在获取公众号 '%s' 的文章列表...\n", nickname)
|
||||
|
||||
// 创建公众号目录
|
||||
officialPath := filepath.Join(cfg.RootPath, "data", nickname)
|
||||
err = utils.CreateDir(officialPath)
|
||||
if err != nil {
|
||||
fmt.Printf("创建目录失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取文章列表
|
||||
articleList := [][]string{}
|
||||
offset := 0
|
||||
pageCount := 0
|
||||
|
||||
for {
|
||||
fmt.Printf("正在获取第 %d 页文章...\n", pageCount+1)
|
||||
result, err := crawler.GetNextList(offset)
|
||||
if err != nil {
|
||||
fmt.Printf("获取第 %d 页文章失败: %v\n", pageCount+1, err)
|
||||
break
|
||||
}
|
||||
|
||||
mFlag, ok := result["m_flag"].(int)
|
||||
if !ok || mFlag == 0 {
|
||||
fmt.Printf("已获取全部文章,共 %d 页\n", pageCount)
|
||||
break
|
||||
}
|
||||
|
||||
passageList, ok := result["passage_list"].([][]string)
|
||||
if !ok {
|
||||
fmt.Printf("文章列表格式错误\n")
|
||||
break
|
||||
}
|
||||
|
||||
articleList = append(articleList, passageList...)
|
||||
|
||||
fmt.Printf("第 %d 页获取成功,新增 %d 篇文章\n", pageCount+1, len(passageList))
|
||||
|
||||
pageCount++
|
||||
offset += 10
|
||||
|
||||
// 检查是否达到指定页数
|
||||
if pages > 0 && pageCount >= pages {
|
||||
fmt.Printf("已获取指定的 %d 页文章\n", pages)
|
||||
break
|
||||
}
|
||||
|
||||
// 防止请求过于频繁
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
fmt.Printf("\n共获取到 %d 篇文章\n", len(articleList))
|
||||
|
||||
// 保存文章列表
|
||||
err = crawler.SaveArticleListToExcel(officialPath, articleList, nickname)
|
||||
if err != nil {
|
||||
fmt.Printf("保存文章列表失败: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("文章列表已保存到: %s\n", filepath.Join(officialPath, "文章列表(article_list)_原始链接.xlsx"))
|
||||
}
|
||||
|
||||
// 转换链接并保存直连链接
|
||||
transformedList := transformLinks(articleList)
|
||||
err = crawler.SaveArticleListToExcel(officialPath, transformedList, nickname)
|
||||
if err != nil {
|
||||
fmt.Printf("保存直连链接失败: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("直连链接已保存到: %s\n", filepath.Join(officialPath, "文章列表(article_list)_直连链接.xlsx"))
|
||||
}
|
||||
}
|
||||
|
||||
// 转换链接列表中的链接
|
||||
func transformLinks(articleList [][]string) [][]string {
|
||||
transformedList := make([][]string, len(articleList))
|
||||
for i, article := range articleList {
|
||||
transformedArticle := make([]string, len(article))
|
||||
copy(transformedArticle, article)
|
||||
// 转换链接,移除amp;
|
||||
if len(article) > 3 {
|
||||
transformedArticle[3] = strings.ReplaceAll(article[3], "amp;", "")
|
||||
}
|
||||
transformedList[i] = transformedArticle
|
||||
}
|
||||
return transformedList
|
||||
}
|
||||
|
||||
// 从access_token中提取必要参数
|
||||
func parseAccessTokenParams(accessToken string) (string, string, string, string, error) {
|
||||
// 从URL中提取必要的参数
|
||||
biz, err := utils.ExtractFromRegex(accessToken, "__biz=([^&]*)")
|
||||
if err != nil {
|
||||
return "", "", "", "", fmt.Errorf("未找到__biz参数")
|
||||
}
|
||||
|
||||
uin, err := utils.ExtractFromRegex(accessToken, "uin=([^&]*)")
|
||||
if err != nil {
|
||||
return "", "", "", "", fmt.Errorf("未找到uin参数")
|
||||
}
|
||||
|
||||
key, err := utils.ExtractFromRegex(accessToken, "key=([^&]*)")
|
||||
if err != nil {
|
||||
return "", "", "", "", fmt.Errorf("未找到key参数")
|
||||
}
|
||||
|
||||
passTicket, err := utils.ExtractFromRegex(accessToken, "pass_ticket=([^&]*)")
|
||||
if err != nil {
|
||||
return "", "", "", "", fmt.Errorf("未找到pass_ticket参数")
|
||||
}
|
||||
|
||||
return biz, uin, key, passTicket, nil
|
||||
}
|
||||
27
backend/cmd/test_content_extraction.go
Normal file
27
backend/cmd/test_content_extraction.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/wechat-crawler/pkg/wechat"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("开始测试文章内容提取功能...")
|
||||
|
||||
// 创建一个简单的爬虫实例
|
||||
crawler := wechat.NewSimpleCrawler()
|
||||
|
||||
// 设置公众号名称(根据实际情况修改)
|
||||
officialAccountName := "验证"
|
||||
|
||||
// 调用GetListArticleFromFile函数测试
|
||||
err := crawler.GetListArticleFromFile(officialAccountName, false, true)
|
||||
if err != nil {
|
||||
fmt.Printf("测试失败: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("测试完成!请检查文章内容是否已正确提取。")
|
||||
}
|
||||
Reference in New Issue
Block a user