Administrator
发布于 2024-06-21 / 39 阅读
4

懂车帝二手车数据爬虫

需要爬取车辆的车名(奥迪)、车型(a6)、二手车价格、表显里程、上牌日期、档位(就是车的型号)、地区、车型、颜色

第一步,分析页面

可以看到价格部分在html源码中不显示,但是在渲染好的页面上是可以显示的

这里用到了字体反爬

字体反爬简介

​ 在 CSS3之前,Web 开发者必须使用用户计算机上已有的字体。目前的技术开发者可以使用@font-face为网页指定字体,开发者可将心仪的字体文件放在 Web 服务器上,并在CSS 样式中使用它。用户使用浏览器访问 Web应用时,对应的字体会被浏览器下载到用户的计算机上。

注:使用自动化selenium也无法获取正常的数据

在网络面板里面筛选字体

下载到本地以后使用FontCreator打开,可以看到具体的编码

现在可以将网页上无法显示的字拉到本地,看一下它的Unicode编码

对应到上面字体文件的编码表,就可以查看到自定义的Unicode对应的字是哪个了

方便起见,使用这段代码把字体文件转为xml文件方便查找

import fontTools
from fontTools.ttLib import TTFont

font = TTFont('6.17\\font.woff2')
font.saveXML('6.17\\font.xml')


print(chr(0xe3e8))
print(chr(0xe3e9))

转换后输出的xml文件

我们只需要GlyphOrder 部分和cmap部分就可以了

根据共同的元素"name"可以生成一个列表,然后再写一个替换函数

def replace_unrecognized_chars(input_str):
    # 映射表,包含code和字符的映射
    glyph_map = {
        0xe439: '0',  #  
        0xe54c: '1',  #  
        0xe463: '2',  #  
        0xe49D: '3',  #  
        0xe41D: '4',  #  
        0xe411: '5',  #  
        0xe534: '6',  #  
        0xe3EB: '7',  #  
        0xe4E3: '8',  #  
        0xe45D: '9',  #  
        0xe40a: ' ',  #  
        0xe525: '年',
        0xe492: '万',
        0xe4a8: '公里',


    }
    
    # 构造一个新的字符串,用于保存替换后的结果
    result = []
    
    # 遍历输入字符串中的每一个字符
    for char in input_str:
        # 获取字符的Unicode码点
        code_point = ord(char)
        
        # 如果码点在映射表中,进行替换;否则,保持原字符
        if code_point in glyph_map:
            result.append(glyph_map[code_point])
        else:
            result.append(char)
    
    # 将列表转换为字符串并返回
    return ''.join(result)

# 测试函数
# sh_price = '\ue4e3.\ue54c\ue4e3\ue40a'
# print(replace_unrecognized_chars(sh_price))

接下来在需要用到这些特殊字体的地方调用这个替换函数就行了

以下是完整爬虫代码

import os
import requests
from fontlist import replace_unrecognized_chars
import xlrd
from xlutils.copy import copy
import xlwt

#程序入口
def main():
    #1. 爬取网页
    datalist = GetData()
    savepath = "6.17/dongchedi.xls"#Excel路径
   

    #3. 保存数据
    SavaData(datalist,savepath)
def GetData():
    # 定义请求URL和请求头
    url = "https://www.dongchedi.com/motor/pc/sh/sh_sku_list?aid=1839&app_name=auto_web_pc"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
        
    }

    datalist = []

    # 定义POST请求的payload
    payload = {
        "sh_city_name": "全国",
        "page" : "1"
    }
    for i in range(2):  # 获取30个页面信息
        payload["page"] = str(i + 1)  # 更新字典中的page键的值
        # print(payload)
        # print(f"第{i+1}页已开始")

        # 发送POST请求
        response = requests.post(url, headers=headers, data=payload)

        # 确保请求成功
        if response.status_code == 200:
            # 解析返回的JSON数据
            jsonusercar = response.json()
            # print(jsonusercar)


            car_info_list = jsonusercar['data']['search_sh_sku_info_list']
            # print(car_info_list)
            
            
            for car_info in car_info_list:
                data = []
                brand_name = car_info['brand_name']
                data.append(brand_name)
                car_name = car_info['title']
                data.append(car_name)
                
                #解密未定义字符
                official_price = replace_unrecognized_chars(car_info['official_price']).rstrip()   
                data.append(official_price)
                sh_price = replace_unrecognized_chars(car_info['sh_price']).rstrip()
                data.append(sh_price)
                sub_title = replace_unrecognized_chars(car_info['sub_title']).rstrip()
                #分割sub_title为上牌日期和公里数
                parts = sub_title.split('|') # 使用'|'字符进行分割
                year_part = parts[0].strip()  # 去除前后的空格
                registration_date = year_part.replace("里程数:", "").strip()  # 去除"里程数:"前缀
                data.append(registration_date)
                kilometres = parts[1].strip()
                data.append(kilometres)
                city_name = car_info['brand_source_city_name']
                data.append(city_name)
                image_url = car_info['image']
                data.append(image_url)
                # print(data)
                datalist.append(data)#追加每页信息
                              
        else:
            print(f"Failed to retrieve data: {response.status_code}")
    return datalist         

        #------------------------------------------------------------
        # print(f"品牌:{brand_name}")
        # print(f"车型:{car_name}")
        # print(f"官方指导价:{official_price}"+"万")
        # print(f"售价:{sh_price}"+"万")
        # print(f"里程数:{kilometres}")
        # print(f"地区:{city_name}")
        # print(f"上牌日期:{registration_date}")
        # print(f"图片链接:{image_url}")
        # print("=" * 50)
        #------------------------------------------------------------
        



#自适应列宽设置
def Auto_Type(datalist,sheet):
    col_width = []

    for i in range(len(datalist[0])):# 每列
        for j in range(len(datalist)):# 每行
            number1 = number2 = 0#统计字符宽度
            for char in datalist[j][i]:
                try:
                    if 0x4e00 <= ord(char) <= 0x9fff or ord(char) == 0x0020:#unicode字符集(utf-8解码)
                        number1 += 2
                    else:
                        number2 += 1
                except Exception as e:
                    if hasattr(e, "code"):  # 出错代码
                        print(e.code)
                    if hasattr(e, "reason"):  # 出错原因
                        print(e.reason)
            number = number1 + number2
            if j == 0:
                col_width.append(number)# 数组增加一个元素
            else:
                if col_width[i] < number:# 获得每列中的内容的最大宽度
                    col_width[i] = number
        width = 256*(col_width[i]+1)
        if width >= 65535:
            width = 65535
        sheet.col(i).width = width#设置列宽


#保存数据到Excel
def SavaData(datalist,savepath):
    if not(os.path.isfile(savepath)):
        book = xlwt.Workbook(encoding="utf-8")#创建文件
        sheet = book.add_sheet("usdecar")#创建表单
        Auto_Type(datalist, sheet)# type: ignore #自适应列宽
        print("表格创建成功\n")
    else:
        rb = xlrd.open_workbook(savepath,formatting_info=True)#打开文件
        book = copy(rb)
        sheet = book.get_sheet(0)#打开表单
        print("表格打开成功\n")
    col = ["品牌","车型","官方指导价","售价","里程数","地区","上牌日期","图片链接"]         
    for i in range(len(datalist[0])):
        sheet.write(0,i,col[i])#写入第一行
    for i in range(len(datalist)):#存入数据
        print("正在写入第%s条"%(i+1))
        data = datalist[i]
        for j in range(len(datalist[0])):
            sheet.write(i+1,j,data[j])

    book.save(savepath)#保存数据

if __name__ == "__main__":
    #调用函数
    main()
    print("爬取完毕")