• 利用爬虫技术自动化采集汽车之家的车型参数数据


    {亿牛云}.png

    导语

    汽车之家是一个专业的汽车网站,提供了丰富的汽车信息,包括车型参数、图片、视频、评测、报价等。如果我们想要获取这些信息,我们可以通过浏览器手动访问网站,或者利用爬虫技术自动化采集数据。本文将介绍如何使用Python编写一个简单的爬虫程序,实现对汽车之家的车型参数数据的自动化采集,并使用亿牛云爬虫代理服务来提高爬虫的稳定性和效率。

    概述

    爬虫技术是一种通过编程模拟浏览器访问网页,解析网页内容,提取所需数据的技术。爬虫程序通常需要完成以下几个步骤:

    • 发送HTTP请求,获取网页源代码
    • 解析网页源代码,提取所需数据
    • 存储或处理提取的数据

    在实际的爬虫开发中,我们还需要考虑一些其他的问题,例如:

    • 如何避免被网站反爬机制识别和封禁
    • 如何提高爬虫的速度和效率
    • 如何处理异常和错误

    为了解决这些问题,我们可以使用一些工具和服务来辅助我们的爬虫开发,例如:

    • 使用requests库来发送HTTP请求,简化网络编程
    • 使用BeautifulSoup库或者XPath语法来解析网页源代码,方便数据提取
    • 使用pandas库或者csv模块来存储或处理提取的数据,支持多种数据格式
    • 使用亿牛云爬虫代理服务来隐藏真实IP地址,防止被网站封禁
    • 使用多线程或者协程来并发发送HTTP请求,提高爬虫的速度和效率
    • 使用try-except语句或者logging模块来处理异常和错误,增加爬虫的稳定性和可维护性

    正文

    下面我们将使用Python编写一个简单的爬虫程序,实现对汽车之家的车型参数数据的自动化采集。我们以"奥迪A4L"为例,获取其所有在售车型的基本参数、动力参数、底盘转向参数、安全装备参数和外部配置参数。

    1. 导入所需库和模块

    首先,我们需要导入以下几个库和模块:

    # 导入requests库,用于发送HTTP请求
    import requests
    
    # 导入BeautifulSoup库,用于解析网页源代码
    from bs4 import BeautifulSoup
    
    # 导入pandas库,用于存储或处理提取的数据
    import pandas as pd
    
    # 导入time模块,用于控制爬虫速度
    import time
    
    # 导入random模块,用于生成随机数
    import random
    
    # 导入threading模块,用于实现多线程爬虫
    import threading
    
    # 导入queue模块,用于实现线程间通信
    import queue
    
    # 导入logging模块,用于记录日志信息
    import logging
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2. 定义全局变量和常量

    接下来,我们需要定义一些全局变量和常量,用于存储或控制爬虫程序的运行状态:

    # 定义奥迪A4L的车型参数页面的URL
    URL = 'https://www.autohome.com.cn/3170/#levelsource=000000000_0&pvareaid=101594'
    
    # 定义亿牛云爬虫代理的域名、端口、用户名、密码
    PROXY_HOST = 'www.16yun.cn'
    PROXY_PORT = '8020'
    PROXY_USER = '16YUN'
    PROXY_PASS = '16IP'
    
    # 定义爬虫代理的HTTP头部
    PROXY_HEADERS = {
        'Proxy-Authorization': 'Basic ' + base64.b64encode((PROXY_USER + ':' + PROXY_PASS).encode()).decode()
    }
    
    # 定义爬虫请求的HTTP头部UserAgent
    HEADERS = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
    }
    
    # 定义爬虫请求的超时时间(秒)
    TIMEOUT = 10
    
    # 定义爬虫请求的重试次数
    RETRY = 3
    
    # 定义爬虫请求的最小间隔时间(秒)
    MIN_DELAY = 1
    
    # 定义爬虫请求的最大间隔时间(秒)
    MAX_DELAY = 3
    
    # 定义爬虫线程的数量
    THREADS = 10
    
    # 定义车型参数数据的列名
    COLUMNS = ['车型', '基本参数', '动力参数', '底盘转向参数', '安全装备参数', '外部配置参数']
    
    # 定义车型参数数据的空列表,用于存储提取的数据
    DATA = []
    
    # 定义车型URL的队列,用于实现线程间通信
    QUEUE = queue.Queue()
    
    # 定义日志格式和级别
    logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=logging.INFO)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    3. 定义发送HTTP请求的函数

    然后,我们需要定义一个函数,用于发送HTTP请求,获取网页源代码:

    def get_html(url):
        # 初始化重试次数
        retry = RETRY
        
        # 循环发送HTTP请求,直到成功或达到重试次数上限
        while retry > 0:
            try:
                # 使用requests库发送HTTP请求,设置代理和超时时间
                response = requests.get(url, headers=HEADERS, proxies={'http': f'http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}'}, timeout=TIMEOUT)
                
                # 判断HTTP响应状态码是否为200,即成功
                if response.status_code == 200:
                    # 返回网页源代码
                    return response.text
                
                # 否则,记录错误信息,并减少重试次数
                else:
                    logging.error(f'请求失败,状态码:{response.status_code},URL:{url}')
                    retry -= 1
            
            # 捕获异常,并记录错误信息,并减少重试次数
            except Exception as e:
                logging.error(f'请求异常,异常信息:{e},URL:{url}')
                retry -= 1
        
        # 如果重试次数为0,说明请求失败,返回空值
        if retry == 0:
            logging.error(f'请求失败,重试次数用尽,URL:{url}')
            return None
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    4. 定义解析网页源代码的函数

    接着,我们需要定义一个函数,用于解析网页源代码,提取所需数据:

    def parse_html(html):
        # 使用BeautifulSoup库解析网页源代码,指定解析器为lxml
        soup = BeautifulSoup(html, 'lxml')
        
        # 使用XPath语法提取车型名称
        car_name = soup.select_one('//div[@class="subnav-title-name"]/a/text()')
        
        # 使用XPath语法提取车型参数表格
        car_table = soup.select_one('//div[@id="config_data"]/div/table')
        
        # 判断车型名称和车型参数表格是否存在
        if car_name and car_table:
            # 初始化车型参数数据的字典,用于存储提取的数据
            car_data = {}
            
            # 将车型名称添加到车型参数数据的字典中,作为第一个键值对
                
            # 使用XPath语法提取车型参数表格的所有行
            car_rows = car_table.select('//tr')
    
            # 遍历车型参数表格的所有行
            for car_row in car_rows:
                # 使用XPath语法提取每一行的第一个单元格,即参数类别
                car_category = car_row.select_one('//th/text()')
    
                # 使用XPath语法提取每一行的第二个单元格,即参数值
                car_value = car_row.select_one('//td/div/text()')
    
                 # 判断参数类别和参数值是否存在
                if car_category and car_value:
                   # 将参数类别和参数值添加到车型参数数据的字典中,作为键值对
                   car_data[car_category] = car_value
    
             # 返回车型参数数据的字典
             return car_data
    
        # 否则,记录错误信息,并返回空值
        else:
          logging.error('解析失败,无法提取车型名称或车型参数表格')
          return None
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    5. 定义存储或处理提取的数据的函数

    然后,我们需要定义一个函数,用于存储或处理提取的数据:

    def save_data(data):
        # 判断数据是否存在
        if data:
            # 将数据添加到车型参数数据的空列表中
            DATA.append(data)
    
            # 记录信息,显示数据已保存
            logging.info(f'数据已保存,车型:{data["车型"]}')
        
        # 否则,记录错误信息,显示数据为空
        else:
            logging.error('数据为空,无法保存')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    6. 定义爬虫线程的类

    接着,我们需要定义一个类,用于实现爬虫线程的功能:

    class SpiderThread(threading.Thread):
        # 重写初始化方法,传入线程名称和队列对象
        def __init__(self, name, queue):
            # 调用父类的初始化方法
            super().__init__()
    
            # 设置线程名称
            self.name = name
    
            # 设置队列对象
            self.queue = queue
        
        # 重写运行方法,实现爬虫逻辑
        def run(self):
            # 记录信息,显示线程开始运行
            logging.info(f'线程{self.name}开始运行')
    
            # 循环从队列中获取车型URL,直到队列为空
            while not self.queue.empty():
                # 从队列中获取车型URL,并移除该元素
                url = self.queue.get()
    
                # 记录信息,显示正在处理该URL
                logging.info(f'线程{self.name}正在处理{url}')
    
                # 调用发送HTTP请求的函数,获取网页源代码
                html = get_html(url)
    
                # 判断网页源代码是否存在
                if html:
                    # 调用解析网页源代码的函数,提取所需数据
                    data = parse_html(html)
    
                    # 调用存储或处理提取的数据的函数,保存或处理数据
                    save_data(data)
                
                # 否则,记录错误信息,显示网页源代码为空
                else:
                    logging.error(f'网页源代码为空,无法处理{url}')
                
                # 生成一个随机数,作为爬虫请求的间隔时间
                delay = random.randint(MIN_DELAY, MAX_DELAY)
    
                # 记录信息,显示爬虫请求的间隔时间
                logging.info(f'线程{self.name}等待{delay}秒')
    
                # 使用time模块暂停爬虫请求的间隔时间
                time.sleep(delay)
            
            # 记录信息,显示线程结束运行
            logging.info(f'线程{self.name}结束运行')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    7. 定义主函数

    最后,我们需要定义一个主函数,用于启动爬虫程序:

    def main():
        # 记录信息,显示爬虫程序开始运行
        logging.info('爬虫程序开始运行')
    
        # 调用发送HTTP请求的函数,获取车型参数页面的网页源代码
        html = get_html(URL)
    
        # 判断网页源代码是否存在
        if html:
            # 使用BeautifulSoup库解析网页源代码,指定解析器为lxml
            soup = BeautifulSoup(html, 'lxml')
    
            # 使用XPath语法提取所有在售车型的URL列表
            car_urls = soup.select('//div[@id="config_data"]/div/div/ul/li/a/@href')
    
            # 判断车型URL列表是否存在
            if car_urls:
                # 遍历车型URL列表
                for car_url in car_urls:
                    # 将车型URL添加到车型URL的队列中
                    QUEUE.put(car_url)
                
                # 初始化一个空列表,用于存储爬虫线程对象
                threads = []
    
                # 遍历爬虫线程的数量范围
                for i in range(THREADS):
                    # 创建一个爬虫线程对象,并传入线程名称和队列对象
                    thread = SpiderThread(f'线程{i+1}', QUEUE)
    
                    # 将爬虫线程对象添加到爬虫线程对象的空列表中
                    threads.append(thread)
                
                # 遍历爬虫线程对象的空列表
                for thread in threads:
                    # 启动爬虫线程
                    thread.start()
                
                # 遍历爬虫线程对象的空列表
                for thread in threads:
                    # 等待爬虫线程结束
                    thread.join()
                
                # 记录信息,显示所有爬虫线程已结束
                logging.info('所有爬虫线程已结束')
            
            # 否则,记录错误信息,显示车型URL列表为空
            else:
                logging.error('车型URL列表为空,无法继续爬取')
        
        # 否则,记录错误信息,显示网页源代码为空
        else:
            logging.error('网页源代码为空,无法继续爬取')
        
        # 判断车型参数数据的空列表是否存在
        if DATA:
            # 使用pandas库创建一个数据框对象,传入车型参数数据的空列表和列名
            df = pd.DataFrame(DATA, columns=COLUMNS)
    
            # 使用pandas库将数据框对象保存为CSV文件,指定文件名和编码格式
            df.to_csv('car_data.csv', encoding='utf-8-sig', index=False)
    
            # 记录信息,显示数据已导出为CSV文件
            logging.info('数据已导出为CSV文件')
        
        # 否则,记录错误信息,显示数据为空
        else:
            logging.error('数据为空,无法导出')
        
        # 记录信息,显示爬虫程序结束运行
        logging.info('爬虫程序结束运行')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    结语

    本文介绍了如何使用Python编写一个简单的爬虫程序,实现对汽车之家的车型参数数据的自动化采集,并使用亿牛云爬虫代理服务来提高爬虫的稳定性和效率。本文只是一个简单的示例,实际的爬虫开发可能需要更多的技巧和知识。希望本文能够对你有所帮助和启发。

  • 相关阅读:
    【古谷彻】算法模板(更新ing···)
    PMP考生如何应对新考纲?看过来!
    Jmeter插件技术:性能测试中服务端资源监控
    常见的八种分布式文件系统介绍
    一个去掉PDF背景水印的思路
    C++中的继承
    vue基础语法01
    leetcode 665. Non-decreasing Array 非递减数列(中等)
    java计算机毕业设计食品销售网站源程序+mysql+系统+lw文档+远程调试
    MARS: An Instance-aware, Modular and Realistic Simulator for Autonomous Driving
  • 原文地址:https://blog.csdn.net/ip16yun/article/details/132979365