GO爬取彼岸网壁纸

时间:2024-10-10 20:45:46

目标

  1. 爬取彼岸图网的精美壁纸
  2. 爬取非会员版的缩略壁纸
  3. 爬取会员版的4K壁纸

网页结构解析

选取一个分类,这里选择的是美食,其url长这样:/4kmeishi/
在这里插入图片描述
谷歌浏览器,点击F12审查元素,有两个地方值得注意,一个是标黄的a标签与标橙的img标签,后续需要从这两个标签获取要爬取的图片的url与name。a标签的href用于4k壁纸的url拼接,img标签的src用于缩略图url的拼接,img标签的alt用于图片的命名
在这里插入图片描述
点进大图,其url为:/tupian/,从上图与下图的对比可知,大图的url由主站的与a标签的fref属性值/tupian/拼接而成。
在这里插入图片描述
要想获取4k图片需要点击上图的下载原图按钮,但是根据参考文献可知这是动态获取的,通过获取data-id的属性值再添加随机数向/e/extend/传参即可,仔细观察可发现图二中的a标签的href属性值中就包括data-id这个值,data-id应该是图片的唯一id。但是批量下载原图是需要会员的,也就是说需要传cookie,否则不能下载原图。
在这里插入图片描述
所以通过上述方式就能轻易获取图片的url与name,那么完整的url长什么样呢
缩略图长这样,完整url见图
在这里插入图片描述
4K壁纸的url:/?id=23196&t=0.1561613,因为这个url输入浏览器直接就下载了(带有cookie的话),所以没有展示图。前文提到是向/e/extend/传参,其实会跳转,但若直接在浏览器输入/e/extend/?id=23196&t=0.1561613反而会出现这种情况
在这里插入图片描述

代码

如何在html中提取目标属性值

在浏览器中的html代码对应位置右击,如图选择copy其xpath,然后需要对拷贝的xpath进行一些修改
在这里插入图片描述
所以拷贝下来的

  1. a标签是这样的://*[@id=“main”]/div[3]/ul/li[1]/a
  2. img标签是这样的: //*[@id=“main”]/div[3]/ul/li[1]/a/img

因为是要获取当前页面的所有图片,所起将其修改为

  1. a标签://*[@id=“main”]/div[3]/ul/li/a
  2. img标签: //*[@id=“main”]/div[3]/ul/li/a/img

使用工具为htmlquery,可参考golang:xpath选择器htmlquery简单用法
当然也可使用正则表达式获取,但是好久没用又搞忘了,就懒得折腾了

文件结构

点击下载原图的时候,可通过查看header来查看cookies,复制就行,我最后将其放在文件里,放成一排,每个cookie由;隔开。
在这里插入图片描述
文件结构如下,是获取缩略图的代码,是获取4K图片的代码。
在这里插入图片描述
代码内均有注释,可按需修改

package main

import (
	"bufio"
	"fmt"
	"/antchfx/htmlquery"
	"/x/net/html/charset"
	"/x/text/encoding"
	"/x/text/encoding/unicode"
	"/x/text/transform"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
)

/**
 * @Author: zx
 * @Date: 2021.05.18
 * @Version: golang1.15
 */

/**
 * @Description: 存放图片的url与对应的名称
 */
type imgAttr struct {
   
	url  string
	name string
}

var (
	// 存放图片链接的数据管道
	chanImages chan imgAttr
	waitGroup  sync.WaitGroup
	// 用于监控协程
	chanTask chan string
	// xpath
	xp      = "//*[@id='main']/div[3]/ul/li/a/img"
	// 爬取页面数量
	chanNum = 26
	// FilePath,存放图片的文件
	filePath = "F:/crawler/bian/meishi/"
	// urlMainPath,大分类的主地址
	mainPath = "/4kmeishi/"
)

/**
 * @Description:就是一个打印err的函数
 * @param err err类型
 * @param why 哪个阶段发生了错误
 */
func HandleError(err error, why string) {
   
	if err != nil {
   
		fmt.Println(why, err)
	}
}

/**
 * @Description: 爬图片链接到管道
 * @param url 传的整页链接
 */
func getImgUrls(url string) {
   
	imgs := getImgs(url)
	// 遍历切片里所有链接,存入数据管道
	for _, img := range imgs {
   
		chanImages <- img
	}
	// 标识当前协程完成
	// 每完成一个任务,写一条数据
	// 用于监控协程知道已经完成了几个任务
	chanTask <- url
	waitGroup.Done()
}

/**
 * @Description: 获取当前页图片链接
 * @param url 当前页的链接
 * @return urls 当前页所有图片的链接
 */
func getImgs(url string) (imgs []imgAttr) {
   
	pageStr := GetPageStr(url)
	root, _ := htmlquery.Parse(strings.NewReader(pageStr))
	results := htmlquery.Find(root, xp)
	fmt.Printf("共找到%d条结果\n", len(results))
	for _, result := range results {
   
		img := imgAttr{
   
			url:  "" + result.Attr[0].Val,
			name: result.Attr[1].Val + ".jpg",
		}
		imgs = append(imgs, img)
	}
	return
}

/**
 * @Description: 抽取根据url获取内容
 * @param url 当前页的链接
 * @return pageStr
 */
func GetPageStr(url string) (pageStr string) {
   
	resp, err := http.