
文章目錄
免責聲明
一、總體思路
二、需要使用的庫
三、具體實施
-
(1)頁面1:
(2)頁面2:
在售頁面
停售頁面
1.第一種方向
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_engine
三、具體實施
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#車型名稱
這樣就拿到了這頁面上的所有車型的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"#車型ID
ts_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:
pass
第二個分欄:
定位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:
pass
else:#跟上面的一樣,正反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:
pass
results = [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)
大功告成,參數都整齊,最后這幾部分代碼拼接寫入CSV文件什么的就OK了,
停售頁面
這個停售頁面跟上面的不一樣哦,有空可以試一下:(打開奧迪A4)
這個頁面管理一下沒有動態數據加載的過程,那就很舒服啦,筆者使用的是BS4加正則表達式,代碼如下:
cxId = "19"#車系ID
url1 = "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)
最后部分代碼拼接一下,可能需要去重,那就是后來的處理了
(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)
第二部:獲取車系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)
最后一步,獲取汽車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)
最后再把幾個部分的代碼拼接一下,寫入文件,跟上面的情況去重看看,會不會多了寫數據。
2.第二種方向

參數對比的頁面,我們點擊選擇車型,按F12進行監聽,等到了json數據,那結果就很明顯了,類似於字典一樣的處理,代碼如下:
import requests
import re
import json
import pymysql
import random
from lxml import etree
from bs4 import BeautifulSoup
import pandas as pd
from pandas.core.frame import DataFrame
cxId = "3972"#車型ID
cx_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("完成")
講到這里,獲取數據基本結束了
四.基本參數寫入數據庫
你這里好了全部的汽車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)#讀取你處理好的汽車ID
df_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:
pass
print("完成")
補充一句,engine.execute(sql)可以直接執行sql語句,可能會更快更方便。
五.總結
謝謝你百忙之中看到這里,辛苦了,上述的方法可能不是最好的方法,也可能數據取不全,只是分享了一些自己的看法,如有不足,一起交流學習。
歡迎關注公眾號:Python爬蟲數據分析挖掘
記錄學習python的點點滴滴;
回復【開源源碼】免費獲取更多開源項目源碼;
公眾號每日更新python知識和【免費】工具;
本文已同步到【開源中國】和【騰訊雲社區】;

