Scrapy 爬虫中的数据去噪和清洗:如何处理和清洗无效、冗余和噪声数据?

2023-04-17 00:00:00 数据 爬虫 清洗

Scrapy 是一个非常强大的爬虫框架,可以帮助用户快速地获取大量的数据,但是数据质量高低却需要靠用户自行处理。在爬虫中获取的数据往往包含了大量的噪声、无效数据和冗余数据,如果不进行清洗和去噪,就会对后续数据分析和处理造成很大的困扰。
在数据清洗和去噪方面,Scrapy 用户可以采取多种方法和技术。下面我们结合范例进行详细介绍和演示。
1. 去重
去重是数据清洗的第一步。当我们从网页中获取到数据时,可能会出现同一条数据被重复获取的情况,需要通过去重操作删除冗余数据。Scrapy 提供了基于哈希算法的去重器类,用户可以使用该类进行去重操作。下面是一个去重的范例代码:

from scrapy.dupefilters import RFPDupeFilter
class CustomDupeFilter(RFPDupeFilter):
    """自定义去重过滤类"""
    def request_fingerprint(self, request):
        """指纹生成函数"""
        # 省略请求参数中与数据无关的部分,如 Cookie 等
        return request.url
class MySpider(scrapy.Spider):
    name = 'myspider'
    custom_settings = {
        'DUPEFILTER_CLASS': 'myproject.custom.CustomDupeFilter'
    }
    def start_requests(self):
        urls = ['http://www.pidancode.com/', 'http://www.pidancode.com/about']
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)
    def parse(self, response):
        pass

在这个例子中,我们首先定义了一个自定义的去重过滤类 CustomDupeFilter,该类继承自 RFPDupeFilter,并实现了一个 request_fingerprint 函数,该函数用于生成请求的指纹。我们将该去重类设置为 Scrapy 的全局配置中,这样在整个爬虫中都会使用该去重器进行去重。
在 request_fingerprint 函数中,我们省略了请求参数中与数据无关的内容,比如 Cookie 等,只针对 URL 进行哈希算法的计算,因为我们判定两个请求是否相同的标准是它们的 URL 是否相同。
2. 去掉 HTML 标签和无效字符
网页中的数据往往带有 HTML 标签和一些无效字符,这有时会影响数据的格式和处理。我们可以使用 Python 第三方库 Beautiful Soup 进行 HTML 标签的去除,使用正则表达式删除无用字符。下面是一个代码演示:

from bs4 import BeautifulSoup
import re
class MySpider(scrapy.Spider):
    name = 'myspider'
    def start_requests(self):
        urls = ['http://www.pidancode.com/', 'http://www.pidancode.com/about']
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)
    def parse(self, response):
        soup = BeautifulSoup(response.text, 'html.parser')
        title = soup.find('title').get_text()  # 去掉 HTML 标签
        content = soup.get_text()
        content = re.sub(r'\W+', '', content)  # 去掉无效字符

在这个例子中,我们使用了 bs4 库对响应的 HTML 进行了解析,并使用 find() 函数获取了 HTML 文档的 title 标签中的文本,这样就自然地去掉了 HTML 标签。同时,我们使用了 re.sub() 函数和正则表达式 \W+,将所有非字母、数字和下划线的字符删除。这样,我们就得到了一个比较干净的文本内容。
3. 数据类型的转换和格式化
在爬虫中,我们可能需要将数据的类型从字符串转换为数字等,或者将数据的格式进行调整。下面是一个例子演示:

class MySpider(scrapy.Spider):
    name = 'myspider'
    def start_requests(self):
        urls = ['http://www.pidancode.com/', 'http://www.pidancode.com/about']
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)
    def parse(self, response):
        price_str = '50.99元'
        price = float(re.findall(r'\d+\.\d+', price_str)[0])
        currency = 'RMB'
        formatted_price = f'{price:.2f} {currency}'

在这个例子中,我们将价格信息从字符串类型转换为了浮点数类型,并用 re.findall() 函数和正则表达式 \d+.\d+ 获取了数字部分。然后,我们将价格格式化为两位小数的字符串,并加上货币符号 RMB,得到了一个更加标准化的文本格式。
4. 数据清洗
数据清洗也是 Scrapy 用户进行数据处理的重要步骤之一。在数据获取过程中,我们可能会遇到一些非常杂乱的数据,比如乱码、特殊符号、缺失值等。下面是一个代码范例,演示了如何针对这些数据进行清洗:

class MySpider(scrapy.Spider):
    name = 'myspider'
    def start_requests(self):
        urls = ['http://www.pidancode.com/', 'http://www.pidancode.com/about']
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)
    def parse(self, response):
        raw_data = response.text
        cleaned_data = raw_data.encode('utf-8').decode(errors='ignore')  # 去掉乱码和非 UTF-8 编码的字符
        cleaned_data = cleaned_data.replace('\r', '').replace('\n', '').replace('\t', '')  # 去掉换行符和制表符
        cleaned_data = re.sub('[^A-Za-z0-9]+', ' ', cleaned_data)  # 去掉特殊符号
        cleaned_data = cleaned_data.strip()  # 去掉文本首尾空格
        if not cleaned_data:  # 如果文本为空,则返回 None
            cleaned_data = None

在这个例子中,我们针对从响应中获取到的原始文本数据进行了多步清洗。首先,我们将文本编码成 UTF-8 格式,并将无法编码的字符用 errors='ignore' 参数去掉。然后,我们使用 replace() 函数和常见的特殊符号去掉了制表符和换行符等。接着,使用了正则表达式 [^A-Za-z0-9]+ 去掉了除字母和数字之外的特殊字符。最后,我们使用了 strip() 函数去掉了首尾空格,并判断了文本是否为空,如果为空则返回 None。这样,我们就得到了一个相对干净的文本数据。

相关文章