ChromeDP Go爬虫在Ubuntu Cron任务中执行异常求助
问题描述
我开发了一个基于chromedp的Go模块,用于登录公司CRM系统并下载报表。部署到Ubuntu 20.04服务器后,编写了bash脚本切换到模块目录并执行go run .命令。通过SSH登录服务器手动执行该bash脚本时程序运行正常,但通过CRON任务执行时,日志仅记录脚本的第一行输出后就停滞。
相关配置
Bash脚本示例
cd ~/projects/DNC_Bot/dnc-bot go run .
Crontab配置示例
30 7 * * 1-5 bash ~/projects/DNC_Bot/dnc-bot > ~/cronLogs/output.log 2>&1
核心Go代码片段
func downloadLists() { // 添加无头模式运行选项 opts := append(chromedp.DefaultExecAllocatorOptions[:], // 设置为false可执行时显示浏览器窗口 chromedp.Flag("headless", true), // chromedp.UserDataDir(""), ) allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...) defer cancel() // 配置自定义日志 taskCtx, cancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf)) defer cancel() // 遍历需要处理的站点 for entity, url := range logicSites { log.Printf("Entity: %s | Logging in to: %s\n", entity, url) // 执行登录并打开案例链接列表 err := chromedp.Run(taskCtx, // 设置下载行为和目录 page.SetDownloadBehavior(page.SetDownloadBehaviorBehaviorAllow).WithDownloadPath("./downloads/"), chromedp.Navigate(url), // 等待用户名输入框可见(页面加载完成) chromedp.WaitVisible(`#txtUsername2`, chromedp.ByID), // 输入账号密码 chromedp.SendKeys(`#txtUsername2`, BOT_USER, chromedp.ByID), chromedp.SendKeys(`#txtPassword2`, BOT_PASS, chromedp.ByID), chromedp.Click(`#btnLogin2`, chromedp.ByID), // 等待首页导航栏可见 chromedp.WaitVisible(`#page-nav`, chromedp.ByID), // 点击案例链接 chromedp.Click(`#page-tree > ul > li:nth-child(4)`, chromedp.ByQuery), chromedp.Sleep(1*time.Second), // 调用下载过滤视图的函数 downloadFilters(), ) if err != nil { log.Fatal(err) } } }
解决方案
1. 修复CRON路径问题
CRON执行时的工作目录和环境变量解析规则和SSH会话不同,建议全部使用绝对路径:
- 修改bash脚本中的
cd命令为绝对路径,比如cd /home/your_username/projects/DNC_Bot/dnc-bot - 把crontab中的日志输出路径改为绝对路径,确保目录存在:
/home/your_username/cronLogs/output.log - 代码中的下载路径
./downloads/替换为绝对路径,比如/home/your_username/projects/DNC_Bot/dnc-bot/downloads/,避免CRON找不到目标目录
2. 补全CRON环境变量
CRON的默认环境变量非常有限,缺少Go命令、Chrome浏览器的路径,以及无头模式需要的显示变量:
- 在bash脚本开头添加环境变量配置:
#!/bin/bash export PATH=/usr/local/go/bin:$PATH # 根据你的Go实际安装路径调整 export DISPLAY=:0 # 无头Chrome必须的显示变量 export HOME=/home/your_username # 明确指定用户根目录 cd /home/your_username/projects/DNC_Bot/dnc-bot go run .
- 或者直接在crontab中定义环境变量:
30 7 * * 1-5 PATH=/usr/local/go/bin:$PATH DISPLAY=:0 bash /home/your_username/projects/DNC_Bot/dnc-bot > /home/your_username/cronLogs/output.log 2>&1
3. 优化chromedp无头模式参数
Ubuntu服务器的无交互环境下,Chrome需要额外参数才能稳定运行,修改Go代码中的opts配置:
opts := append(chromedp.DefaultExecAllocatorOptions[:], chromedp.Flag("headless", true), chromedp.Flag("no-sandbox", true), // 无交互环境下必须禁用沙箱 chromedp.Flag("disable-dev-shm-usage", true), // 解决/dev/shm空间不足导致的崩溃问题 )
4. 增强日志排查能力
当前日志仅捕获脚本输出,无法定位chromedp内部的停滞点,建议添加调试日志:
- 修改Go代码的日志配置,输出chromedp的详细日志:
// 输出chromedp内部日志,方便定位问题 taskCtx, cancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(func(format string, v ...interface{}) { log.Printf("chromedp: "+format, v...) }))
- 在bash脚本中添加阶段调试输出:
#!/bin/bash echo "[$(date)] 脚本启动" >> /home/your_username/cronLogs/debug.log export PATH=/usr/local/go/bin:$PATH echo "[$(date)] PATH已设置为: $PATH" >> /home/your_username/cronLogs/debug.log cd /home/your_username/projects/DNC_Bot/dnc-bot echo "[$(date)] 当前工作目录: $(pwd)" >> /home/your_username/cronLogs/debug.log go run . >> /home/your_username/cronLogs/output.log 2>&1 echo "[$(date)] 脚本执行结束" >> /home/your_username/cronLogs/debug.log
5. 检查权限配置
确保CRON执行用户(即你的服务器用户名)拥有相关目录的读写权限:
# 确保日志目录可读写 chmod 755 /home/your_username/cronLogs # 确保Go模块目录可访问,下载目录可写入 chmod -R 755 /home/your_username/projects/DNC_Bot/dnc-bot mkdir -p /home/your_username/projects/DNC_Bot/dnc-bot/downloads chmod 775 /home/your_username/projects/DNC_Bot/dnc-bot/downloads
内容的提问来源于stack exchange,提问作者Hector Lopez
相关产品推荐
相关产品推荐

