# 9.2 爬取汽车之家 二手车产品库

项目地址：<https://github.com/go-crawler/car-prices>

## 目标

最近经常有人在耳边提起汽车之家，也好奇二手车在国内的价格是怎么样的，因此本次的目标站点是 [汽车之家](https://car.autohome.com.cn/2sc/440399/index.html) 的二手车产品库

![image](https://i.loli.net/2018/03/30/5abe47f82a01f.png)

分析目标源：

* 一页共24条
* 含分页，但这个老产品库，在100页后会存在问题，因此我们爬取99页
* 可以获取全部城市
* 共可爬取 19w+ 数据

## 开始

爬取步骤

* 获取全部的城市
* 拼装全部城市URL入队列
* 解析二手车页面结构
* 下一页URL入队列
* 循环拉取所有分页的二手车数据
* 循环拉取队列中城市的二手车数据
* 等待，确定队列中无新的 URL
* 爬取的二手车数据入库

### 获取城市

![image](https://i.loli.net/2018/03/31/5abeff11ef583.png)

通过页面查看，可发现在城市筛选区可得到全部的二手车城市列表，但是你仔细查阅代码。会发现它是JS加载进来的，城市也统一放在了一个变量中

![image](https://i.loli.net/2018/03/31/5abf056389cf0.png)

有两种提取方法

* 分析JS变量，提取出来
* 直接将 `areaJson` 复制出来作为变量解析

在这里我们直接将其复制粘贴出来即可，因为这是比较少变动的值

### 获取分页

![image](https://i.loli.net/2018/03/31/5abf08ec812e2.png)

通过分析页面可以得知分页链接是有一定规律的，例如：`/2sc/hangzhou/a0_0msdgscncgpi1ltocsp2exb4/`，可以发现 `sp%d`，`sp` 后面为页码

按照常理，可以通过预测所有分页链接，推入队列后 `go routine` 一波 即可快速拉取

但是在这老产品库存在一个问题，在超过 100 页后，下一页永远是 101 页

![image](https://i.loli.net/2018/03/31/5abf0e1e623ec.png)

因此我们采取比较传统的做法，通过拉取下一页的链接去访问，以便适应可能的分页链接改变； 100 页以后的分页展示也很奇怪，先忽视

### 获取二手车数据

页面结构较为固定，常规的清洗 HTML 即可

```
func GetCars(doc *goquery.Document) (cars []QcCar) {
    cityName := GetCityName(doc)
    doc.Find(".piclist ul li:not(.line)").Each(func(i int, selection *goquery.Selection) {
        title := selection.Find(".title a").Text()
        price := selection.Find(".detail .detail-r").Find(".colf8").Text()
        kilometer := selection.Find(".detail .detail-l").Find("p").Eq(0).Text()
        year := selection.Find(".detail .detail-l").Find("p").Eq(1).Text()

        kilometer = strings.Join(compileNumber.FindAllString(kilometer, -1), "")
        year = strings.Join(compileNumber.FindAllString(strings.TrimSpace(year), -1), "")
        priceS, _ := strconv.ParseFloat(price, 64)
        kilometerS, _ := strconv.ParseFloat(kilometer, 64)
        yearS, _ := strconv.Atoi(year)

        cars = append(cars, QcCar{
            CityName: cityName,
            Title: title,
            Price: priceS,
            Kilometer: kilometerS,
            Year: yearS,
        })
    })

    return cars
}
```

## 数据

![image](https://i.loli.net/2018/03/31/5abf1d8042196.png)

![image](https://i.loli.net/2018/04/01/5abfbaa14b09c.png)

在各城市的平均价格对比中，我们可以发现北上广深里的北京、上海、深圳都在榜单上，而近年势头较猛的杭州直接占领了榜首，且后几名都有一些距离

而其他城市大致都是梯级下降的趋势，看来一线城市的二手车也是不便宜了，当然这只是均价

![image](https://i.loli.net/2018/03/31/5abf1dbc665f2.png)

我们可以看到价格和公里数的对比，上海、成都、郑州的等比差异是有点大，感觉有需求的话可以在价格和公里数上做一个衡量

![image](https://i.loli.net/2018/03/31/5abf1e1434edc.png)

这图有点儿有趣，粗略的统计了一下总公里数。在前几张图里，平均价格排名较高的统统没有出现在这里，反倒是呼和浩特、大庆、中山等出现在了榜首

是否侧面反应了一线城市的车辆更新换代较快，而较后的城市的车辆倒是换代较慢，公里数基本都杠杠的

![image](https://i.loli.net/2018/03/31/5abf1e4936640.png)

通过对标题的分析，可以得知车辆产品库的命名基本都是品牌名称+自动/手动+XXXX款+属性，看标题就能知道个概况了

## 参考

### 爬虫项目地址

* <https://github.com/go-crawler/car-prices>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://eddycjy.gitbook.io/golang/di-10-ke-pa-chong/cars.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
