ITPub博客

首页 > 应用开发 > Python > python爬虫汽车之家全车型及基本参数入数据库(截止50524个数据)(详解)

python爬虫汽车之家全车型及基本参数入数据库(截止50524个数据)(详解)

Python 作者:qwer1030274531 时间:2020-09-16 13:25:33 0 删除 编辑

  文章目录

  免责声明

  一、总体思路

  二、需要使用的库

  三、具体实施

  1.第一种方向

  (1)页面1:

  在售页面

  停售页面

  (2)页面2:

  2.第二种方向

  四.基本参数写入数据库

  五.总结


免责声明

本人新手小白,看到网上很多类似的文章,本着实践,交流学习目的,如侵,立删。
如文章被转载利用,出现一切后果与本人(笔者)无关。

一、总体思路

目的:汽车之家官网所有的车型以及他的基本参数这些,我们知道每个车的ID不一样,那我们找到所有的ID,在找到他们的基本参数那就不是问题了。
分析网站:
闲话少说:第一种方向:是按照品牌一级一级往下找,比较繁琐;
第二种方向:按照车型对比界面,找到JSON提取数据,这个比较容易点
(那我们用第二种简单的方案不就行了,我当时也是这样觉得,但这样真的取得全吗?是所以的数据吗?带着这些疑问去实践不就好了)

二、需要使用的库

可能用到的库:

from selenium import webdriver
from pandas.core.frame import DataFrame
import json
import random
import pymysql
import re, time
import socket
import io
import sys
import os
import pandas as pd
import requests
from lxml import etree
from pyquery import PyQuery as pq
from bs4 import BeautifulSoup
from sqlalchemy import create_engine12345678910111213141516

三、具体实施

1.第一种方向

(1)页面1:

在这里插入图片描述
按F12打开开发者工具,监听一下动态页面刷到https://www.autohome.com.cn/grade/carhtml/B.html,那我们就可以联想到这些按A-Z排序遍历一下就可以把所有的品牌和对应车系ID拿下来了
在这里插入图片描述

分析一下需要的数据在那些标签,很整齐,建议使用BS4解析,代码如下(示例):

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"}#模拟游览器headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
        random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
        random.randrange(1, 200, 20))#IP地址构造url = 'https://www.autohome.com.cn/grade/carhtml/%d.html'for i in range(ord("A"),ord("Z")+1):
    U=chr(i)
    new_url = "https://www.autohome.com.cn/grade/carhtml/%s.html" %U#字符串拼接A-Z字母
    #new_url = format(url%i)
    respone = requests.get(url=new_url,headers=headers)#发送请求
    respone.encoding = 'gbk'
    page_text = respone.text
    soup = BeautifulSoup(page_text, 'lxml')
    dls = soup.findAll("dl")#bs4直接定位所有的dl标签再遍历
    for dl in dls:
        brandId = dl.get("id")#品牌ID
        brandName = dl.find("dt").text#品牌名称
        # print(brandId,brandName)
        logo = dl.find("img")#loge
        cxzs = dl.find_all(class_="rank-list-ul")#直接定位这个车系的车系标签
        for cxz in cxzs:
            zm = cxz.findPrevious().text#车系名称
            cxs = cxz.findAll("li")
            for cx in cxs:
                try:
                    cxId = cx.get("id").replace("s", "")#车型ID
                    cxName = cx.find("a").text#车型名称12345678910111213141516171819202122232425262728293031

这样就拿到了这页面上的所有车型的ID,我们点击这些车系,会弹出宁一个窗口,但有2种情况,一个是停售界面,一个是在售界面,笔者没有分清楚折个界面(感觉很乱),只有一个个带进去了:

在售页面

在这里插入图片描述
在售界面的第一个分栏:也就是2种界面,一个在售一个停售:

在这里插入图片描述
我们获取停售的href标签网址
在这里插入图片描述
如果实在太多,就可以查询我们需要的数据,然后这样的界面就很规范,取出数据也很轻松:

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"}headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
        random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
        random.randrange(1, 200, 20))brandId = "3170"#车型IDts_url = "https://www.che168.com/autoseries/list.aspx?seriesid=%s"%(cxId)content = requests.get(url=ts_url, headers=headers).text
soup = BeautifulSoup(content, "lxml")cars = soup.findAll("li")for c in cars:
   try:#异常处理,不是每一个车型页面都有的
       if c.find("input").get("all") == "0":
           car_id = c.find("input").get("specid")#汽车ID
           car_name = c.text.replace("\n","")#汽车名称
           # print(brandId,brandName,cxId,cxName,car_id,car_name)
               
   except:
       pass1234567891011121314151617181920212223

第二个分栏: http://ask.baikezh.com/ 在这里插入图片描述
定位li标签,我需要的是他的href标签,形成网址,后续的就会动态数据传输
在这里插入图片描述
在这里插入图片描述
这样的数据很显而易见了 ,但也别忘前面的数据,代码如下:

cxId = "3170"url = "https://www.autohome.com.cn/%s"%(cxId)headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"}headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
    random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
    random.randrange(1, 200, 20))response = requests.get(url=url,headers=headers).text
soup = BeautifulSoup(response,'lxml')list1 = soup.findAll(class_="spec-wrap active")p1 = []#建空列表,为后面append函数传参数for l in list1:
    if l.find_all("dd") != []:#肯定会有的车系没有,所以我们进行了判断
        dds = l.find_all("dd")
        for dd in dds:
            #�
            carName1 = dd.find("a").text#汽车名称
            carName1.replace("�","")
            if dd.find("p").get("data-gcjid") == None:#进行判断
                car_id1s = dd.find("a").get("href")#汽车ID
                car_id1 = re.findall(r'-?\d+\.?\d*e?-?\d*?', car_id1s)[0]
                yearName1 = re.findall(r'-?\d+\.?\d*e?-?\d*?', carName1)[0] + "款"#年款
                p1.append(car_id1)
                p1.append(carName1)
                p1.append(yearName1)
            else:
                car_id1 = dd.find("p").get("data-gcjid")
                yearName1 = dd.get("data-sift1")
                p1.append(car_id1)
                p1.append(carName1)
                p1.append(yearName1)
            # print(car_id,carName,yearName)
    else:
        continue#上面是第一个在售页面原本就有的数据,下面我们就要获取其中参数构造请求获得数据,也就是停售款下拉表的数据tree = etree.HTML(response)#这里用了XPATH定位解析if tree.xpath('//div[@class="athm-title__sub"]//li[@class="more-dropdown"]/ul/li') == []:#进行了判断,不是每一个车型网页都有这个标签,
    list2 = tree.xpath('//div[@class="athm-title__sub"]//li[1]/ul/li')
    for li in list2:
        syearid = li.xpath('./a/@data-yearid')[0]#获得了很重要的参数syearid
        # print(cxId,syearid)
        url1 = "https://www.autohome.com.cn/ashx/car/Spec_ListByYearId.ashx?seriesid=%s&syearid=%s" % (cxId, syearid)#进行了字符串的拼接
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"
        }
        headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
            random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
            random.randrange(1, 200, 20))
        # car_id,carName,brandId, brandName, cxId, cxName,yearName
        try:#异常处理
            content = requests.get(url=url1, headers=headers).json()#json数据格式,类似于字典,理清层级关系
            for group1 in content:
                for group2 in group1["speclist"]:
                    car_id2 = group2["specid"]#汽车ID
                    carName2 = group2["specname"]#汽车名称
                    yearName2 = re.findall(r'-?\d+\.?\d*e?-?\d*?', carName2)[0] + "款"#年款
                    # print(car_id, carName, yearName)
                    p1.append(car_id2)
                    p1.append(carName2)
                    p1.append(yearName2)
        except:
            passelse:#跟上面的一样,正反2个方面
    list2 = tree.xpath('//div[@class="athm-title__sub"]//li[2]/ul/li')
    # print(list2)
    for li in list2:
        syearid = li.xpath('./a/@data-yearid')[0]
        # print(cxId,syearid)
        url1 = "https://www.autohome.com.cn/ashx/car/Spec_ListByYearId.ashx?seriesid=%s&syearid=%s" % (cxId, syearid)
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"
        }
        headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
            random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
            random.randrange(1, 200, 20))
        # car_id,carName,brandId, brandName, cxId, cxName,yearName
        try:
            content = requests.get(url=url1, headers=headers).json()
            for group1 in content:
                for group2 in group1["speclist"]:
                    car_id2 = group2["specid"]
                    carName2 = group2["specname"]
                    yearName2 = re.findall(r'-?\d+\.?\d*e?-?\d*?', carName2)[0] + "款"
                    # print(car_id, carName, yearName)
                    p1.append(car_id2)
                    p1.append(carName2)
                    p1.append(yearName2)
        except:
            passresults = [p1[i:i+3] for i in range(0,len(p1),3)]#3个参数为一组for z in results:
    td1 = [str(i) for i in z]
    td2 = ','.join(td1)  # 列表和字符串之间的转换
    print(td2)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101

大功告成,参数都整齐,最后这几部分代码拼接写入CSV文件什么的就OK了,

停售页面

这个停售页面跟上面的不一样哦,有空可以试一下:(打开奥迪A4)
在这里插入图片描述
这个页面管理一下没有动态数据加载的过程,那就很舒服啦,笔者使用的是BS4加正则表达式,代码如下:

cxId = "19"#车系IDurl1 = "https://www.autohome.com.cn/%s"%(cxId)headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"}headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
    random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
    random.randrange(1, 200, 20))content = requests.get(url=url1,headers=headers).text
soup = BeautifulSoup(content, "lxml")cars = soup.findAll(class_="name")#标签定位,这里有点麻烦,以后改进for c in cars:
    #print(c)
    if c.find("a") != None:#判断排除一些不需要的,正则提取字符串的数字也就是汽车ID
        car_ids = c.find('a').get("href")
        car_id = re.findall(r'-?\d+\.?\d*e?-?\d*?', car_ids)[0]#汽车ID
        car_Name = c.find("a").get("title")#汽车名称
        yearName = re.findall(r'-?\d+\.?\d*e?-?\d*?', car_Name)[0] + "款"#年款
        print(car_id,car_Name,yearName)123456789101112131415161718192021

最后部分代码拼接一下,可能需要去重,那就是后来的处理了

(2)页面2:

为什么会有页面呢,因为后面数据对比发现,页面1没有的数据,页面2有,也就是说他这个不全:
在这里插入图片描述
按F12,监听一下动态加载的页面,我就会发现,品牌和车型都在这个列表上:
第一步获取品牌,品牌ID和品牌的这个界面网址:

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"}headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
        random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
        random.randrange(1, 200, 20))url = 'https://car.autohome.com.cn/AsLeftMenu/As_LeftListNew.ashx?typeId=1%20&brandId=0%20&fctId=0%20&seriesId=0'product_response = requests.get(url=url,headers=headers).text
soup = BeautifulSoup(product_response,'lxml')product_lis = soup.findAll("li")#标签定位for pr in product_lis:
    brandId = pr.get("id").replace("b","")#品牌ID
    brandName = pr.find("a").text#品牌名称
    brand_url = "https://car.autohome.com.cn" + pr.find("a").get("href")#品牌网址
    print(brandId,brandName,brand_url)123456789101112131415

第二部:获取车系ID和车系网址:
在这里插入图片描述
也就是获取A标签中的href和文本内容,代码如下:

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"}headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
        random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
        random.randrange(1, 200, 20))brand_url = 'https://car.autohome.com.cn/price/brand-238.html'response1 = requests.get(url=brand_url,headers=headers).text
soup = BeautifulSoup(response1,'lxml')dls = soup.findAll(class_="list-dl")#标签定位for dl in dls:
    cxNames = dl.find_all(class_="list-dl-text")
    for dd in cxNames:
        cxName_list = dd.find_all("a")
        for a in cxName_list:
            cxName = a.text#车型名称
            cx_href = a.get("href")
            cx_id = re.findall('\d+', cx_href)[0]#车型ID
            cx_url = "https://car.autohome.com.cn" + cx_href#车型网址
            print(cxName,cx_id,cx_url)123456789101112131415161718192021

最后一步,获取汽车ID和名称:
在这里插入图片描述
显示渠道这2个标签的网址,然后我们在对网址发送请求,解析提取我们想要的数据,代码如下:

cx_url = "https://car.autohome.com.cn/price/series-3170.html#pvareaid=2042205"#奥迪A3的网址headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"}headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
        random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
        random.randrange(1, 200, 20))response2 = requests.get(url=cx_url,headers=headers).text
tree = etree.HTML(response2)lis = tree.xpath('//div[@class="tab-nav border-t-no"]/ul/li')#这里我们用了Xath解析p1 = []#创建空列表,传参for li in lis:
    if li.xpath('./a/@href') != []:#依旧是判断,有可能这界面没有网址
        href_url = "https://car.autohome.com.cn" + li.xpath('./a/@href')[0]
        # print(href_url)
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"
        }
        headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
            random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
            random.randrange(1, 200, 20))
        response3 = requests.get(url=href_url, headers=headers).text#再次发送请求
        soup = BeautifulSoup(response3,'lxml')
        if soup.findAll(class_="interval01-list") != []:#进行判段,可能会没有返回的是空列表
            uls = soup.findAll(class_="interval01-list")
            for ul in uls:
                t1 = ul.find_all("li")
                for t2 in t1:
                    car_id = t2.get("data-value")#汽车ID
                    p1.append(car_id)
                    car_name = t2.find(class_="interval01-list-cars-infor").find("a").text#汽车名称
                    p1.append(car_name)
        if soup.findAll(class_="page") != []:#考虑到有没有分页,依然是判断
            page_list = soup.findAll(class_="page")
            for page in page_list:
                pages = page.find_all("a")
                for pa in pages:
                    if pa.get("class") == None:
                        href_url2 = "https://car.autohome.com.cn" + pa.get("href")#构造分页的网址
                        # print(href_url2)
                        headers = {
                            "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"
                        }
                        headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
                            random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
                            random.randrange(1, 200, 20))
                        response4 = requests.get(url=href_url2, headers=headers).text
                        soup4 = BeautifulSoup(response4, 'lxml')
                        if soup4.findAll(class_="interval01-list") != []:判断可能会没有数据,防止报错
                            uls4 = soup4.findAll(class_="interval01-list")
                            for ul4 in uls4:
                                t14 = ul4.find_all("li")
                                for t24 in t14:
                                    car_id4 = t24.get("data-value")#汽车ID
                                    p1.append(car_id4)
                                    car_name4 = t24.find(class_="interval01-list-cars-infor").find("a").text#汽车名称
                                    p1.append(car_name4)result1 = [p1[i:i + 2] for i in range(0, len(p1), 2)]#2个参数每一组for z in result1:
    td1 = [str(i) for i in z]
    td2 = ','.join(td1)#列表与字符串之间的传唤
    print(td2)12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667

最后再把几个部分的代码拼接一下,写入文件,跟上面的情况去重看看,会不会多了写数据。

2.第二种方向

在这里插入图片描述
参数对比的页面,我们点击选择车型,按F12进行监听,等到了json数据,那结果就很明显了,类似于字典一样的处理,代码如下:

import requestsimport reimport jsonimport pymysqlimport randomfrom lxml import etreefrom bs4 import BeautifulSoupimport pandas as pdfrom pandas.core.frame import DataFrame
cxId = "3972"#车型IDcx_url = "https://car.autohome.com.cn/duibi/ashx/specComparehandler.ashx?type=1&seriesid=%s&format=json"%(cxId)headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"}headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
        random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
        random.randrange(1, 200, 20))response2 = requests.get(url=cx_url,headers=headers).json()p2 = []p3 = []for group1 in response2["List"]:
    # print(group1["List"])
    for group2 in group1["List"]:
        car_id = group2["I"]
        p2.append(car_id)
        car_name = group2["N"]
        p2.append(car_name)
        # print(car_id,car_name)
        p1 = [car_id,car_name]
        p3.append(p1)print(p3)result2 = [p2[i:i + 2] for i in range(0, len(p2), 2)]new = DataFrame(p3,columns=['cxId','cxName'])#转成DataFrame格式print(new)new.to_excel("new.xls")#写入文件print("完成")12345678910111213141516171819202122232425262728293031323334353637

讲到这里,获取数据基本结束了

四.基本参数写入数据库


你这里好了全部的汽车ID,然后去车型对比页遍历这些ID网站,获得json数据,获取即可,最后写入数据库:

table = 'cars_parameters'#表名dicts = {
        'car_id': "",
        'parameter_name': "",
        'parameter_value': "",
                        }#创建空字典keys = ','.join(dicts.keys())values = ','.join(["%s"] * len(dicts))sql1 = 'INSERT INTO {table}({keys}) VALUES ({values})'.format(table=table, keys=keys,
                                                              values=values)#构造动态sql语句db = pymysql.connect(
                            host='localhost',
                            user='root',
                            password='123',
                            port=3306,
                            db='cars_home',
                            charset='utf8'
                        )#连接数据库cursor = db.cursor()#获取游标sql = 'CREATE TABLE IF NOT EXISTS cars_parameters(car_id VARCHAR(255) NOT NULL,parameter_name VARCHAR(255),parameter_value VARCHAR (255))'cursor.execute(sql)#创建数据表cars_parameters,并执行headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36"}headers["X-Forwarded-For"] = "%s.%s.%s.%s" % (
        random.randrange(1, 200, 20), random.randrange(1, 200, 20), random.randrange(1, 200, 20),
        random.randrange(1, 200, 20))df = pd.read_excel("3.xlsx",usecols=[0],names=None)#读取你处理好的汽车IDdf_li = df.values.tolist()results = []for s_li in df_li:
    results.append(s_li[0])for q in results:
    car_id = q    print(car_id)
    
    try:
        url2 = "https://carif.api.autohome.com.cn/Car/Spec_ParamListBySpecList.ashx?speclist=%s" % (
            car_id)
        response = requests.get(url=url2,headers=headers).json()#json数据
        groups = response["result"]["paramtypeitems"]
        group_name_list = []
        group_name_list2 = []
        for group in groups:#循环遍历自己想要的数据
            group_Name = group["name"]
            # print(group_Name)
            group1 = group["paramitems"]
            # print(group_Name,group1)
            for group2 in group1:
                group_Name_1 = group2["name"]
                group3 = group2["valueitems"]
                # print(group_Name,group_Name_1,group3)
                for group4 in group3:
                    carID = group4["specid"]
                    group_Name_2 = group4["value"]
                    # group_name_list.append(group_Name_1)
                    # group_name_list2.append(group_Name_2)
                    #print(car_id,group_Name_1,group_Name_2)
                    dicts = {
                        'car_id': car_id,
                        'parameter_name': group_Name_1,
                        'parameter_value': group_Name_2,
                    }#得出的值传入字典
                    try:
                        cursor.execute(sql1, tuple(dicts.values()))#元组数据插入表
                    except:
                        db.rollback()
                    else:
                        db.commit()
    except:
        passprint("完成")12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879

补充一句,engine.execute(sql)可以直接执行sql语句,可能会更快更方便。本人测试截止2020年9月10日取出50524个汽车ID,应该远远不止这些。

五.总结

谢谢你百忙之中看到这里,辛苦了,上述的方法可能不是最好的方法,也可能数据取不全,只是分享了一些自己的看法,如有不足,一起交流学习。


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30239065/viewspace-2721608/,如需转载,请注明出处,否则将追究法律责任。

全部评论

注册时间:2015-05-08

  • 博文量
    60
  • 访问量
    23849