Python网络爬虫中的编码乱码如何解决

项目场景:

开发一个Python爬虫程序,需要爬取某电商网站的商品信息(包括商品名称、价格、评论等),并将数据保存为CSV文件。项目使用requests库进行网页请求,Beautiful Soup进行解析,需要处理大量包含中文、emoji等特殊字符的数据。


问题描述

在运行爬虫程序时,遇到以下问题:

  1. 保存的CSV文件打开后显示乱码
  2. 某些特殊商品名称显示为问号或方块
  3. emoji表情无法正确显示
  4. 读取CSV文件时出现UnicodeDecodeError异常

问题代码示例:

python 复制代码
import requests
from bs4 import BeautifulSoup
import csv

def crawl_product_info():
    url = "http://example.com/products"
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    # 提取商品信息
    products = []
    for item in soup.find_all('div', class_='product-item'):
        name = item.find('h2').text
        price = item.find('span', class_='price').text
        comments = item.find('div', class_='comments').text
        products.append([name, price, comments])
    
    # 保存到CSV
    with open('products.csv', 'w') as f:
        writer = csv.writer(f)
        writer.writerows(products)

原因分析:

  1. 网页编码问题:

    • requests默认使用其自动识别的编码
    • 某些网站的编码声明可能不准确
    • response.text可能使用错误的编码解码
  2. CSV文件编码问题:

    • 默认使用系统编码(Windows中文系统通常是cp936)
    • 没有指定UTF-8 BOM标记
    • Excel打开UTF-8文件可能无法正确识别编码
  3. 特殊字符处理:

    • emoji字符超出基本Unicode平面
    • 某些特殊符号需要特殊编码处理
    • 不同Python版本的默认编码处理可能不同

解决方案:

  1. 完整的改进版代码:
python 复制代码
import requests
from bs4 import BeautifulSoup
import csv
import codecs
from typing import List, Dict

class ProductCrawler:
    def __init__(self):
        self.session = requests.Session()
        # 设置默认请求头
        self.session.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        }

    def get_page_content(self, url: str) -> str:
        """获取页面内容并确保编码正确"""
        response = self.session.get(url)
        # 显式设置编码
        response.encoding = response.apparent_encoding
        return response.text

    def parse_product(self, html: str) -> List[Dict]:
        """解析商品信息"""
        soup = BeautifulSoup(html, 'html.parser')
        products = []
        
        for item in soup.find_all('div', class_='product-item'):
            try:
                product = {
                    'name': self._clean_text(item.find('h2').text),
                    'price': self._clean_text(item.find('span', class_='price').text),
                    'comments': self._clean_text(item.find('div', class_='comments').text)
                }
                products.append(product)
            except AttributeError as e:
                print(f"解析商品信息失败: {e}")
                continue
                
        return products

    def _clean_text(self, text: str) -> str:
        """清理文本数据"""
        if text is None:
            return ""
        # 移除特殊字符和空白
        return text.strip().replace('\n', ' ').replace('\r', '')

    def save_to_csv(self, products: List[Dict], filename: str):
        """保存数据到CSV文件"""
        try:
            # 使用utf-8-sig编码(带BOM),确保Excel能正确识别
            with codecs.open(filename, 'w', encoding='utf-8-sig') as f:
                writer = csv.DictWriter(f, fieldnames=['name', 'price', 'comments'])
                writer.writeheader()
                writer.writerows(products)
        except Exception as e:
            print(f"保存CSV文件失败: {e}")
            raise

    def crawl_and_save(self, url: str, output_file: str):
        """爬取并保存数据的主函数"""
        try:
            html = self.get_page_content(url)
            products = self.parse_product(html)
            self.save_to_csv(products, output_file)
            print(f"成功爬取并保存{len(products)}条商品信息")
        except Exception as e:
            print(f"爬取过程发生错误: {e}")
  1. 使用示例:
python 复制代码
def main():
    crawler = ProductCrawler()
    url = "http://example.com/products"
    
    try:
        crawler.crawl_and_save(url, "products.csv")
    except Exception as e:
        print(f"程序执行失败: {e}")

if __name__ == "__main__":
    main()
  1. 关键改进点:
  • 使用response.apparent_encoding自动识别网页编码
  • 使用utf-8-sig编码保存CSV(带BOM标记)
  • 添加文本清理函数处理特殊字符
  • 使用异常处理机制提高程序稳定性
  • 采用类的方式组织代码,提高可维护性
  1. 读取CSV文件的正确方式:
python 复制代码
def read_csv(filename: str) -> List[Dict]:
    """正确读取CSV文件的方法"""
    try:
        with codecs.open(filename, 'r', encoding='utf-8-sig') as f:
            reader = csv.DictReader(f)
            return list(reader)
    except UnicodeDecodeError:
        # 尝试使用其他编码
        with codecs.open(filename, 'r', encoding='gb18030') as f:
            reader = csv.DictReader(f)
            return list(reader)

通过以上优化,程序可以正确处理各种编码情况,确保数据的完整性和可读性。特别是在处理中文和特殊字符时,不会再出现乱码问题。

相关推荐
qq_447663051 小时前
java-----多线程
java·开发语言
a辰龙a1 小时前
【Java报错解决】警告: 源发行版 11 需要目标发行版 11
java·开发语言
听海边涛声1 小时前
JDK长期支持版本(LTS)
java·开发语言
IpdataCloud1 小时前
Java 获取本机 IP 地址的方法
java·开发语言·tcp/ip
MyMyMing1 小时前
Java的输入和输出
java·开发语言
Easonmax1 小时前
【javaSE】内部类(来自类和对象的补充)
开发语言·javascript·ecmascript
云夏之末1 小时前
【Java报错已解决】java.lang.UnsatisfiedLinkError
java·开发语言
eybk2 小时前
Qpython+Flask监控添加发送语音中文信息功能
后端·python·flask
li星野2 小时前
QT:图像上绘制图形
开发语言·qt
花落已飘2 小时前
RK3568中使用QT opencv(显示基础图像)
开发语言·qt·opencv