查看原文
其他

python实战| 二手车难买?手把手带你爬取瓜子二手车-二级页面

是沐沐呀 GOGO数据 2022-08-01





需求分析





首先我们先来看一下今天的任务:


【1】爬取地址 

瓜子网 - 我要买车 

https://www.guazi.com/xa/buy/o1/


【2】爬取目标 

所有汽车的车辆概况 、车龄、全款价、汽车原价 


【3】爬取分析 

*********一级页面需抓取*********** 

1、车辆详情页的链接 


*********二级页面需抓取*********** 

1、汽车排量

2、过户情况 

3、变速箱

4、表显里程 

5、最低首付



右键点击检查,可以发现:页面40辆车的信息都在在浏览器中源码的

40个li当中。

这些汽车的车辆概况 、车龄、全款价、汽车原价等都

可以在当前页面中获取到如下图所示:



所以我们第一步先要获取到当前页面的40个li,

然后循环获取内部的具体信息。



发送请求


我们使用xpath来获取这些信息:

# 请求链接
url = 'https://www.guazi.com/cd/buy/o1/#bread'

# 添加headers模拟浏览器
headers = {
    'Referer''https://www.guazi.com/xa/buy/o1/',
    'Cookie''uuid=aecbdf7d-8648-4f28-dbf9-902293bbf045; clueSourceCode=%2A%2300; user_city_id=176; ganji_uuid=6311203881588826872627; guazitrackersessioncadata=%7B%22ca_kw%22%3A%22%25e7%2593%259c%25e5%25ad%2590%25e4%25ba%258c%25e6%2589%258b%25e8%25bd%25a6%22%7D; sessionid=d173d24e-e570-4019-cc19-47bcd5e33348; lg=1; Hm_lvt_bf3ee5b290ce731c7a4ce7a617256354=1623491103; close_finance_popup=2021-06-12; cainfo=%7B%22ca_a%22%3A%22-%22%2C%22ca_b%22%3A%22-%22%2C%22ca_s%22%3A%22pz_baidu%22%2C%22ca_n%22%3A%22pcbiaoti%22%2C%22ca_medium%22%3A%22-%22%2C%22ca_term%22%3A%22-%22%2C%22ca_content%22%3A%22-%22%2C%22ca_campaign%22%3A%22-%22%2C%22ca_kw%22%3A%22%25e7%2593%259c%25e5%25ad%2590%25e4%25ba%258c%25e6%2589%258b%25e8%25bd%25a6%22%2C%22ca_i%22%3A%22-%22%2C%22scode%22%3A%22-%22%2C%22keyword%22%3A%22-%22%2C%22ca_keywordid%22%3A%22-%22%2C%22display_finance_flag%22%3A%22-%22%2C%22platform%22%3A%221%22%2C%22version%22%3A1%2C%22client_ab%22%3A%22-%22%2C%22guid%22%3A%22aecbdf7d-8648-4f28-dbf9-902293bbf045%22%2C%22ca_city%22%3A%22xa%22%2C%22sessionid%22%3A%22d173d24e-e570-4019-cc19-47bcd5e33348%22%7D; _gl_tracker=%7B%22ca_source%22%3A%22-%22%2C%22ca_name%22%3A%22-%22%2C%22ca_kw%22%3A%22-%22%2C%22ca_id%22%3A%22-%22%2C%22ca_s%22%3A%22self%22%2C%22ca_n%22%3A%22-%22%2C%22ca_i%22%3A%22-%22%2C%22sid%22%3A64163631266%7D; cityDomain=xa; preTime=%7B%22last%22%3A1623491941%2C%22this%22%3A1623491102%2C%22pre%22%3A1623491102%7D; Hm_lpvt_bf3ee5b290ce731c7a4ce7a617256354=1623491941',
    'User-Agent': str(UserAgent().random)
        }
# 获取浏览器响应
resp = requests.get(url, headers = headers).text
# 转换数据格式
html = etree.HTML(resp)
# 获取当前页面的所有li标签
lis = html.xpath("//ul[@class='carlist clearfix js-top']/li")
print(len(lis))
'''
40
'''


成功获取到当前页面40个li标签。



解析一级页面



刚才我们已经知道汽车的所有信息都在li标签之内,所以我们使用for循环来获取所有的内部元素

        for li in lis:

          car_info = li.xpath('./a/h2/text()')
          car_info = ''.join(car_info)                    # 汽车概况

          car_age = li.xpath('./a/div[1]/text()[1]')      # 车龄
          car_age = ''.join(car_age)

          car_money = li.xpath('./a/div[2]/p/text()')
          car_money = (''.join(car_money)).strip()+'万'        # 全款价

          car_money_before = li.xpath('./a/div[2]/em/text()')
          car_money_before = ''.join(car_money_before)        # 汽车原价


当前页面我们要获取的元素就是这些,但是我们的目标不止于此,还有二级页面的汽车排量、过户情况、变速箱、表显里程、最低首付。

所以接下来如何解析二级页面从而获取到这些元素才是我们的重点目标。



解析二级页面



现在我们在当前页面点击图中所标记的宝马X3,点击之后跳转到车辆详情页面,这就是我们要分析的二级页面。



二级页面的信息请求和一级页面信息获取是一样的,都需要通过浏览器去发送对于请求。

所以我们先要分析的就是二级页面的url
https://www.guazi.com/cd/7316979f21e70f6dx.htm#fr_page=list&fr_pos=city&fr_no=6

从上面图片可以看出,当前宝马所在位置是7,所以末尾参数fr_no=6,
初步分析汽车位置和这个参数是一一对应的。
我们可以多点开几个页面进行分析。

https://www.guazi.com/bj/ee3a894d99b6410ax.htm#fr_page=list&fr_pos=city&fr_no=0https://www.guazi.com/wh/b380ae546e997ad9x.htm#fr_page=list&fr_pos=city&fr_no=1https://www.guazi.com/luoyang/0b81b54964780535x.htm#fr_page=list&fr_pos=city&fr_no=2

分析结果如我们预想,图片编号和fr_no下标是一一对应的。
但是除了链接开头的https://www.guazi.com中间参数都是没有任何规律可言的。
既然点击一级页面可以进入到二级页面,那么它们之间肯定是有沟通桥梁的。

所以我们继续去分析页面,打开一级页面,我么可以发现在li标签在有一个href的属性如下:


我们点击这个链接发现可以成功的跳转到二级页面的,所以这就是我们要找的链接。



但是我们再仔细看看这个链接其实是不完整的,相比于正常链接,他缺少前面的https://www.guazi.com


所以我们拿到这个链接之后还需进一步的拼接能组成完整的二级页面汽车详情链接。



简单捋一下就是从一级页面获取href属性再在其前面拼接上缺少的https://www.guazi.com就是二级页面的请求连接。

所以在之前获取的汽车的车辆概况 、车龄、全款价、汽车原价的基础上还要再多加一个href的属性值。同样我们使用xpath来获取。

  # 下一页数据连接
  links = li.xpath('./a/@href')
  print(links)
  
  '''
  ['/bj/ee3a894d99b6410ax.htm#fr_page=list&fr_pos=city&fr_no=0']
  ['/wh/b380ae546e997ad9x.htm#fr_page=list&fr_pos=city&fr_no=1']
  ['/bj/1f7953fa3159e3bfx.htm#fr_page=list&fr_pos=city&fr_no=2']
  ['/sz/b1f6fcfb41ad1a71x.htm#fr_page=list&fr_pos=city&fr_no=3']
  ['/sjz/2d81bfce151d5ce1x.htm#fr_page=list&fr_pos=city&fr_no=4']
  ['/luoyang/0b81b54964780535x.htm#fr_page=list&fr_pos=city&fr_no=5']
  ['/sz/76ce1ce87c34eeb3x.htm#fr_page=list&fr_pos=city&fr_no=6']
  ['/cd/7316979f21e70f6dx.htm#fr_page=list&fr_pos=city&fr_no=7']
  ['/dl/074437d845f51653x.htm#fr_page=list&fr_pos=city&fr_no=8']
  ['/dl/41f793fdc202d875x.htm#fr_page=list&fr_pos=city&fr_no=9']
  ['/hengshui/0d9a9d418978d26fx.htm#fr_page=list&fr_pos=city&fr_no=10']
  ['/cd/f8d9c5284a51c294x.htm#fr_page=list&fr_pos=city&fr_no=11']
  ['/cq/182607ed564f84f4x.htm#fr_page=list&fr_pos=city&fr_no=12']
  ['/huaibei/ea5cd321d449a733x.htm#fr_page=list&fr_pos=city&fr_no=13']
  ['/nn/ee581d9e587ad043x.htm#fr_page=list&fr_pos=city&fr_no=14']
    ...................
  '''


成功获取到这些半拉子链接,点击是没有反应的,还需要加上https://www.guazi.com

 # 下一页数据连接
    links = li.xpath('./a/@href')
    x = 'https://www.guazi.com'
    page_down = [x + i for i in links]
    print(page_down)
  
  '''
    ['https://www.guazi.com/bj/ee3a894d99b6410ax.htm#fr_page=list&fr_pos=city&fr_no=0']
    ['https://www.guazi.com/sy/6c8bdb7d5d4e3e1fx.htm#fr_page=list&fr_pos=city&fr_no=1']
    ['https://www.guazi.com/wh/b380ae546e997ad9x.htm#fr_page=list&fr_pos=city&fr_no=2']
    ['https://www.guazi.com/bj/1f7953fa3159e3bfx.htm#fr_page=list&fr_pos=city&fr_no=3']
    ['https://www.guazi.com/sz/b1f6fcfb41ad1a71x.htm#fr_page=list&fr_pos=city&fr_no=4']
    ['https://www.guazi.com/sjz/2d81bfce151d5ce1x.htm#fr_page=list&fr_pos=city&fr_no=5']
    ['https://www.guazi.com/luoyang/0b81b54964780535x.htm#fr_page=list&fr_pos=city&fr_no=6']
    ['https://www.guazi.com/sz/76ce1ce87c34eeb3x.htm#fr_page=list&fr_pos=city&fr_no=7']
    ['https://www.guazi.com/cd/7316979f21e70f6dx.htm#fr_page=list&fr_pos=city&fr_no=8']
    ['https://www.guazi.com/dl/074437d845f51653x.htm#fr_page=list&fr_pos=city&fr_no=9']
    ['https://www.guazi.com/dl/41f793fdc202d875x.htm#fr_page=list&fr_pos=city&fr_no=10']
    ['https://www.guazi.com/hengshui/0d9a9d418978d26fx.htm#fr_page=list&fr_pos=city&fr_no=11']
    ['https://www.guazi.com/cd/f8d9c5284a51c294x.htm#fr_page=list&fr_pos=city&fr_no=12']
    ['https://www.guazi.com/cq/182607ed564f84f4x.htm#fr_page=list&fr_pos=city&fr_no=13']
    ['https://www.guazi.com/huaibei/ea5cd321d449a733x.htm#fr_page=list&fr_pos=city&fr_no=14']
      ...................
  '''


成功的获取到了完整的二级页面url。
好累.....


继续拿刚才的二级页面的宝马来说,链接我们已经拿到了,继续发送请求来获取汽车排量、过户情况、变速箱、表显里程、最低首付。
接下来我们将一级页面和二级页面的汽车全部信息都给打印出来。

    response = requests.get(page, headers = headers)
    if response.status_code == 200:
        html = etree.HTML(response.text)

        car_displace = html.xpath("//li[@class='three']/span/text()")
        car_displace = ''.join(car_displace)        # 汽车排量

        car_transf = html.xpath("//ul[@class='basic-eleven clearfix']/li[@class='seven']/div/text()")
         car_transf = ''.join(car_transf).strip()      # 过户情况

        car_change = html.xpath("//ul[@class='assort clearfix']/li[@class='last']/span/text()")
        car_change = ''.join(car_change)          # 变速箱

        car_mile = html.xpath("//li[@class='two']/span/text()")
        car_mile = ''.join(car_mile)    # 表显里程

        car_pay = html.xpath("//a[@class='loanbox js-loan']/span[@class='f24']/text()")
        car_pay = ''.join(car_pay)
        if car_pay == '':
            car_pay = '该车暂不支持分期'             # 最低首付)
        print(car_info, car_age, car_money, car_money_before, car_displace, car_transf, car_change, car_mile, car_pay)
        
  '''
      奥迪Q5 2012款 2.0TFSI 舒适型 2012年 15.80万 52.31万 2.0T 0次过户 自动 5.94万公里 5.09
      起亚 秀尔 2012款 1.6L AT Premium 2013年 4.35万 13.87万 1.6L 0次过户 自动 6.54万公里 1.65
      现代ix35 2013款 2.0L 自动两驱智能型GLS 国IV 2014年 7.28万 21.36万 2.0L 0次过户 自动 8.38万公里 2.53
      丰田 汉兰达 2015款 2.0T 四驱豪华版 7座 2017年 26.00万 32.00万 2.0T 1次过户 自动 9.7万公里 8.15
      现代 名图 2014款 1.8L 自动尊贵型DLX 2014年 7.50万 17.35万 1.8L 0次过户 自动 8.81万公里 2.6
      奔驰B级 2012款 B 180(进口) 2014年 10.20万 30.18万 1.6T 0次过户 自动 6.53万公里 3.41
      别克 君威 2015款 1.6T 时尚技术型 2016年 8.60万 21.70万 1.6T 0次过户 自动 3.78万公里 2.93
      奔驰C级 2013款 C 300 运动型 Grand Edition 2014年 14.80万 50.80万 3.0L 0次过户 自动 8.21万公里 4.79
      宝马X3 2013款 xDrive20i 豪华型(进口) 2013年 18.50万 54.16万 2.0T 0次过户 自动 9.66万公里 5.9
      斯巴鲁 森林人 2011款 2.5XS 自动豪华版 2011年 7.68万 29.29万 2.5L 1次过户 自动 10.88万公里 该车暂不支持分期
      Jeep 指南者 2013款 2.4L 四驱豪华版(进口) 2013年 8.28万 28.97万 2.4L 0次过户 自动 6.84万公里 2.83
      哈弗H6 2013款 运动版 1.5T 手动两驱精英型 2014年 5.10万 13.44万 1.5T 1次过户 手动 7.31万公里 1.88
      菲亚特 菲翔 2012款 1.4T 自动劲享版 2013年 3.87万 15.07万 1.4T 1次过户 自动 9.23万公里 1.51
      东风风光580 2017款 1.5T CVT智联型 2018年 7.58万 13.35万 1.5T 0次过户 自动 4.22万公里 2.62
      雪佛兰 科鲁兹 2013款 1.6L SE MT 2014年 3.88万 13.01万 1.6L 0次过户 手动 6.44万公里 1.51
      吉利 缤瑞 2018款 14T CVT缤致版 2018年 6.90万 10.51万 1.4T 0次过户 自动 1.41万公里 2.42
      本田 杰德 2017款 210TURBO CVT豪华版 5座 2017年 12.68万 18.01万 1.5T 5次过户 自动 3.35万公里 4.15
      海马 丘比特 2013款 1.3L 手动炫酷版 2014年 1.98万 5.85万 1.3L 0次过户 手动 3.59万公里 该车暂不支持分期
      本田 雅阁 2018款 260TURBO 精英版 国V 2018年 15.58万 20.60万 1.5T 0次过户 自动 4.83万公里 5.02
      哈弗F5 2019款 国潮版 1.5T i潮 国VI 2019年 8.68万 12.81万 1.5T 0次过户 自动 2.7万公里 2.95
      奔驰E级 2015款 E 260 L 运动型 2014年 35.00万 50.80万 2.0T 2次过户 自动 5.8万公里 10.85
      哈弗H6 2013款 运动版 1.5T 手动两驱精英型 2015年 5.50万 13.44万 1.5T 1次过户 手动 9.1万公里 2
      起亚K3 2016款 1.6L 自动GLS 2017年 6.98万 12.90万 1.6L 0次过户 自动 3.44万公里 2.44
      福特 福克斯 2015款 两厢 1.6L 自动舒适型 2016年 6.30万 13.55万 1.6L 2次过户 自动 6.12万公里 2.24
      ...........
  '''


保存数据



我们已经成功获取到了单页数据,接下来我们将这些数据
保存到excel中便于后续分析。
    ws = op.Workbook()
    wb = ws.create_sheet(index=0)

    wb.cell(row=1, column=1, value='车辆概况')
    wb.cell(row=1, column=2, value='车龄')
    wb.cell(row=1, column=3, value='全款价')
    wb.cell(row=1, column=4, value='汽车原价')
    wb.cell(row=1, column=5, value='汽车排量')
    wb.cell(row=1, column=6, value='过户情况')
    wb.cell(row=1, column=7, value='变速箱')
    wb.cell(row=1, column=8, value='表显里程')
    wb.cell(row=1, column=9, value='最低首付')
    ws.save('瓜子二手车.xlsx')


但是我们的目的是获取全部的数据50页2000+条车辆信息,所以我们要使用for循环来获取全部数据。


    for page in range(150+1):
        url = f'https://www.guazi.com/cd/buy/o{page}/#bread'

为了防止被反爬,我让程序加上了休眠。所以速度方面不是很理想。
time.sleep(random.random() * 3)


接下来我会使用多线程生产者消费者模式来加快爬虫信息获取速度,

为了更加直观的展示我还准备对部分信息进行可视化展示

有兴趣的小伙伴记得明天来围观啊!

搞定Python不就那么点事吗?

动态网页实战| python爬虫+前端框架Bootstrap

爬了2576张美女网小姐姐私房照,感叹:Scrapy是真方便啊

说说我在爬虫中常用的8个技巧,最后一个屡试不爽

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存