python爬蟲汽車之家全車型及基本引數入資料庫(截止50524個資料)(詳解)

qwer1030274531發表於2020-09-16

  文章目錄

  免責宣告

  一、總體思路

  二、需要使用的庫

  三、具體實施

  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開啟開發者工具,監聽一下動態頁面刷到,那我們就可以聯想到這些按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 = '%d.html'for i in range(ord("A"),ord("Z")+1):
    U=chr(i)
    new_url = "%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

第二個分欄: 在這裡插入圖片描述
定位li標籤,我需要的是他的href標籤,形成網址,後續的就會動態資料傳輸
在這裡插入圖片描述
在這裡插入圖片描述
這樣的資料很顯而易見了 ,但也別忘前面的資料,程式碼如下:

cxId = "3170"url = "%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 = "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 = "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 = "%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 = '%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 = "("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 = '(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 = "車型網址
            print(cxName,cx_id,cx_url)123456789101112131415161718192021

最後一步,獲取汽車ID和名稱:
在這裡插入圖片描述
顯示渠道這2個標籤的網址,然後我們在對網址傳送請求,解析提取我們想要的資料,程式碼如下:

cx_url = "奧迪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 = "('./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 = "("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 = "%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 = "%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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章