文章采集调用(下采集神器:chromedp+HeadlessChrome安装安装)

优采云 发布时间: 2022-01-06 06:06

  文章采集调用(下采集神器:chromedp+HeadlessChrome安装安装)

  最近在采集微信文章的时候,遇到了一个比较棘手的问题。通过搜狗搜索的微信搜索模式,正常的直接抓取页面的方式无法绕过搜狗搜索的验证。所以成功使用gorequest采集到微信文章。

  选择 chromedp + Headless Chrome

  面对采集的目的没有达到的问题,我是不是就此放弃了?显然这是不可能的。不就是签名验证嘛,只要不要求输入验证码,总有办法解决的(蒽,一般的验证码也可以解决)。于是牺牲了golang下的采集神器:chromedp。

  简单来说,chromedp是golang语言用来调用Chrome调试协议来模拟浏览器行为的一个包,可以简单的驱动浏览器。使用的前提很简单,就是在电脑上安装Chrome浏览器。

  Chrome浏览器的安装在Windows和macOS下没有问题,在桌面版Linux下也没有问题。但是如果要在Linux服务器版本上安装Chrome,就没有那么简单了。至少目前,Chrome 还没有可以直接安装在服务器上的软件包。

  但是你必须放弃你刚刚想到的想法吗?当然这是不可能的。翻阅chromedp文档,我刚刚找到了一段:

  最简单的方法是在 chromedp/headless-shell 映像中运行使用 chromedp 的 Go 程序。该图像收录 headless-shell,这是一种较小的 Chrome 无头构建,chromedp 可以立即找到它。

  他的意思是:最简单的方法就是用chromedp调用chromedp/headless-shell镜像。chromedp/headless-shell 是一个 docker 镜像,收录一个较小的 Chrome 无头浏览器。

  好的,既然是docker镜像,我们就用docker安装。

  首先登录我们的linux服务器,下面的操作就认为你已经登录到linux服务器了。

  安装 docker 并安装 chromedp/headless-shell

  如果您的服务器已经安装了 docker,请跳过此步骤。

  使用yum安装docker

  yum install docker

复制代码

  安装完成后,此时无法直接使用docker,需要执行以下命令激活

  systemctl daemon-reload

service docker restart

复制代码

  然后安装 chromedp/headless-shell 镜像

  docker pull chromedp/headless-shell:latest

复制代码

  等待安装完成,然后运行docker镜像

  docker run -d -p 9222:9222 --rm --name headless-shell chromedp/headless-shell

复制代码

  运行后,测试chrome是否正常:

  curl http://127.0.0.1:9222/json/version

复制代码

  如果看到类似下面的内容,说明chrome浏览器工作正常

  {"浏览器": "Chrome/96.0.4664.110","协议版本": "1.3","用户代理":" Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36","V8-Version": "9.6.180.21","WebKit-Version": "537.36 (@d5ef0e8214bc14c9b5bbf69a1515e431394c62a6)","webSocketDebuggerUrl": "ws://127.0.0.1/devers-browse/dev22921 -4d5b-b9e6-37d634aa719a"}

  chromedp代码调用chromedp/headless-shell采集微信公众号文章内容

  Linux下可以正常使用Headless Chrome无头浏览器。剩下的就是调用它的代码了。

  现在我们开始编写采集微信文章使用的chrome代码:

  定义关键字,artile struct.go

  package main

type Keyword struct {

Id int64 `json:"id"`

Name string `json:"name"`

Level int `json:"level"`

ArticleCount int `json:"article_count"`

LastTime int64 `json:"last_time"` //上次执行时间

}

type Article struct {

Id int64 `json:"id"`

KeywordId int64 `json:"keyword_id"`

Title string `json:"title"`

Keywords string `json:"keywords"`

Description string `json:"description"`

OriginUrl string `json:"origin_url"`

Status int `json:"status"`

CreatedTime int `json:"created_time"`

UpdatedTime int `json:"updated_time"`

Content string `json:"content"`

ContentText string `json:"-"`

}

复制代码

  编写核心代码 core.go

  package main

import (

"context"

"fmt"

"github.com/chromedp/cdproto/cdp"

"github.com/chromedp/chromedp"

"log"

"net"

"net/url"

"strings"

"time"

)

func CollectArticleFromWeixin(keyword *Keyword) []*Article {

timeCtx, cancel := context.WithTimeout(GetChromeCtx(false), 30*time.Second)

defer cancel()

var collectLink string

err := chromedp.Run(timeCtx,

chromedp.Navigate(fmt.Sprintf("https://weixin.sogou.com/weixin?p=01030402&query=%s&type=2&ie=utf8", keyword.Name)),

chromedp.WaitVisible(`//ul[@class="news-list"]`),

chromedp.Location(&collectLink),

)

if err != nil {

log.Println("读取搜狗搜索列表失败1:", keyword.Name, err.Error())

return nil

}

log.Println("正在采集列表:", collectLink)

var aLinks []*cdp.Node

if err := chromedp.Run(timeCtx, chromedp.Nodes(`//ul[@class="news-list"]//h3//a`, &aLinks)); err != nil {

log.Println("读取搜狗搜索列表失败2:", keyword.Name, err.Error())

return nil

}

var articles []*Article

for i := 0; i < len(aLinks); i++ {

href := aLinks[i].AttributeValue("href")

href, _ = joinURL("https://weixin.sogou.com/", href)

article := &Article{}

err = chromedp.Run(timeCtx,

chromedp.Navigate(href),

chromedp.WaitVisible(`#js_article`),

chromedp.Location(&article.OriginUrl),

chromedp.Text(`#activity-name`, &article.Title, chromedp.NodeVisible),

chromedp.InnerHTML("#js_content", &article.Content, chromedp.ByID),

chromedp.Text("#js_content", &article.ContentText, chromedp.ByID),

)

if err != nil {

log.Println("读取搜狗搜索列表失败3:", keyword.Name, err.Error())

}

log.Println("采集文章:", article.Title, len(article.Content), article.OriginUrl)

articles = append(articles, article)

}

return articles

}

// 重组url

func joinURL(baseURL, subURL string) (fullURL, fullURLWithoutFrag string) {

baseURL = strings.TrimSpace(baseURL)

subURL = strings.TrimSpace(subURL)

baseURLObj, _ := url.Parse(baseURL)

subURLObj, _ := url.Parse(subURL)

fullURLObj := baseURLObj.ResolveReference(subURLObj)

fullURL = fullURLObj.String()

fullURLObj.Fragment = ""

fullURLWithoutFrag = fullURLObj.String()

return

}

//检查是否有9222端口,来判断是否运行在linux上

func checkChromePort() bool {

addr := net.JoinHostPort("", "9222")

conn, err := net.DialTimeout("tcp", addr, 1*time.Second)

if err != nil {

return false

}

defer conn.Close()

return true

}

// ChromeCtx 使用一个实例

var ChromeCtx context.Context

func GetChromeCtx(focus bool) context.Context {

if ChromeCtx == nil || focus {

allocOpts := chromedp.DefaultExecAllocatorOptions[:]

allocOpts = append(allocOpts,

chromedp.DisableGPU,

chromedp.Flag("blink-settings", "imagesEnabled=false"),

chromedp.UserAgent(`Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36`),

chromedp.Flag("accept-language", `zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6`),

)

if checkChromePort() {

// 不知道为何,不能直接使用 NewExecAllocator ,因此增加 使用 ws://127.0.0.1:9222/ 来调用

c, _ := chromedp.NewRemoteAllocator(context.Background(), "ws://127.0.0.1:9222/")

ChromeCtx, _ = chromedp.NewContext(c)

} else {

c, _ := chromedp.NewExecAllocator(context.Background(), allocOpts...)

ChromeCtx, _ = chromedp.NewContext(c)

}

}

return ChromeCtx

}

复制代码

  写入入口文件main.go

  package main

import "log"

func main() {

word := Keyword{

Name: "golang",

}

result := CollectArticleFromWeixin(&word)

for i, v := range result {

log.Println(i, v.Title, len(v.Content), v.OriginUrl)

log.Println("纯内容:", v.ContentText)

}

}

复制代码

  运行结果测试:

  

  伟大的结果出来了。

  如果您对此代码感兴趣,可以从这里获取 /fesiong/gob...。

  本采集代码仅供研究学习之用,不得用于非法用途。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线