Qwen1.5-1.8B GPTQ与Python爬虫结合:智能数据清洗与摘要生成
Qwen1.5-1.8B GPTQ与Python爬虫结合:智能数据清洗与摘要生成
你是不是也遇到过这种情况?辛辛苦苦写了个爬虫,从网上抓下来一堆数据,结果打开一看——格式乱七八糟,广告词和正文混在一起,关键信息淹没在废话里,想用还得手动整理半天。
我之前做数据分析项目时,经常被这种“脏数据”搞得头疼。爬虫能帮你把数据“拿回来”,但怎么把数据“变干净”、“变有用”,才是更费功夫的事。直到我开始尝试把大模型和爬虫结合起来,才发现原来数据处理可以这么轻松。
今天要跟你分享的,就是把Qwen1.5-1.8B这个轻量级模型,通过GPTQ量化后,接入到Python爬虫流程里的实战方案。简单来说,就是让模型帮你自动清洗数据、提取关键信息,还能生成内容摘要。你只需要专注写爬虫逻辑,脏活累活交给模型来处理。
1. 为什么爬虫需要“智能后处理”?
做爬虫的朋友都知道,从网上抓下来的数据,很少是“即拿即用”的。我总结了一下,大概有这么几个让人头疼的问题:
格式混乱是常态。同一篇文章,可能段落之间夹杂着广告、导航栏、版权声明,甚至还有“点击展开更多”这样的交互元素。你想要的正文内容,被这些无关信息切割得支离破碎。
信息冗余严重。很多网站为了SEO或者用户体验,会在正文前后加上大量重复的、概括性的文字。这些内容对机器来说可能是“噪音”,清洗掉它们才能看到数据的“真面目”。
关键信息提取费时费力。比如从一篇产品评测里找价格、型号、优缺点;从新闻里提取时间、地点、人物、事件。这些工作如果靠写规则,每个网站都得单独适配,累死人。
数据理解成本高。抓下来几十篇长文章,你想快速了解每篇讲什么,难道要一篇篇读过去吗?手动写摘要又不现实。
传统的做法是写一堆正则表达式、XPath或者CSS选择器,针对特定网站做清洗规则。这种方法有两个致命缺点:一是开发维护成本高,网站一改版,规则可能就失效了;二是泛化能力差,换个网站,规则基本得重写。
而大模型带来的思路转变是:我们不再教程序“规则”,而是教它“理解”。让模型像人一样,看懂网页内容,然后帮我们整理出想要的信息。Qwen1.5-1.8B GPTQ版本,因为模型小、经过量化后对资源要求低,正好适合集成到爬虫这种对响应速度有一定要求的应用场景里。
2. 整体架构:让爬虫和模型协同工作
这套方案的核心思想很简单,就是在你原有的爬虫流程后面,加一个“智能处理层”。你可以把它想象成一条流水线:爬虫是原料采集工,模型是精加工车间。
整个数据流转大概是这样的:
爬虫抓取原始网页 → 初步解析(获取文本)→ 送入模型处理 → 输出结构化/摘要化结果 → 存入数据库或文件第一步,爬虫照常工作。你用Requests、Scrapy、Selenium或者Playwright,把目标网页的HTML抓下来。这一步没有任何改变。
第二步,进行初步的文本提取。用BeautifulSoup、lxml或者parsel这样的库,把HTML标签去掉,拿到大段的纯文本。这时候的文本虽然没了标签,但还是很“脏”。
第三步,这是关键的一步,把文本交给模型。我们搭建一个本地的模型服务,或者调用API,把上一步得到的文本送进去。告诉模型:“嘿,帮我把这段文字清洗干净,再提取一下关键信息,最后生成个摘要。”
第四步,接收并保存结果。模型会返回处理后的干净文本、提取的信息(比如JSON格式)和摘要。你可以把这些结果直接存到数据库里,或者输出成文件。
这样做的好处是,你的爬虫脚本几乎不用大改,只是在数据解析后增加了一个调用模型的步骤。整个架构非常灵活,模型可以部署在本地,也可以放在服务器上,通过HTTP接口来调用。
3. 环境准备与模型部署
在开始写代码之前,我们需要把环境和模型准备好。Qwen1.5-1.8B是一个1.8B参数的中英文模型,本身不算大,但直接加载对有些开发机可能还是有压力。所以我们会用到它的GPTQ量化版本,量化后模型体积更小,运行速度更快,对显存的要求也大大降低。
3.1 基础环境搭建
首先,确保你的Python环境是3.8或以上版本。然后,我们安装一些核心的库。
# 安装模型推理和量化相关的库 pip install transformers optimum auto-gptq # 安装爬虫和数据处理常用库 pip install requests beautifulsoup4 scrapy pandas # 如果需要用到异步或者Web服务,可以安装这些 pip install fastapi uvicorntransformers是Hugging Face的模型库,optimum和auto-gptq是为了更好地支持量化模型的加载和推理。爬虫部分我们用requests和beautifulsoup4,它们足够轻量简单。
3.2 获取与加载GPTQ模型
GPTQ是一种模型量化技术,简单理解就是给模型“瘦身”,在尽量保持效果的前提下,减少模型占用的存储空间和内存,让它跑得更快。Qwen1.5-1.8B的GPTQ版本,你可以在Hugging Face模型库找到,通常文件名会带有-GPTQ或-gptq-4bit这样的后缀。
这里假设你已经下载好了模型文件,放在本地的./models/Qwen1.5-1.8B-GPTQ目录下。加载模型的代码如下:
from transformers import AutoTokenizer, pipeline from auto_gptq import AutoGPTQForCausalLM model_name_or_path = "./models/Qwen1.5-1.8B-GPTQ" # 加载分词器 tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, use_fast=True) # 加载GPTQ量化模型 model = AutoGPTQForCausalLM.from_quantized( model_name_or_path, device="cuda:0", # 使用GPU,如果是CPU则改为 "cpu" use_triton=False, inject_fused_attention=False, # 对于Qwen模型,通常设为False trust_remote_code=True # 信任来自远程的代码(如模型自定义代码) ) # 创建一个文本生成的管道 pipe = pipeline( "text-generation", model=model, tokenizer=tokenizer, max_new_tokens=512, # 生成文本的最大长度 temperature=0.7, # 控制随机性,越低越确定,越高越有创意 do_sample=True, )这段代码做了几件事:加载分词器(负责把文字转换成模型能看懂的数字)、加载量化后的模型、最后创建一个生成管道,方便我们后面调用。device参数根据你的硬件来选,有NVIDIA显卡就用cuda:0,没有就用cpu,只是速度会慢一些。
3.3 封装一个简单的模型服务
为了在爬虫中方便调用,我们可以把模型功能封装成一个类或者函数。这里我写一个简单的类,提供清洗、提取和摘要三个核心功能。
class SmartDataProcessor: def __init__(self, model_pipeline): self.pipe = model_pipeline def _call_model(self, prompt): """调用模型的统一方法""" try: outputs = self.pipe(prompt) generated_text = outputs[0]['generated_text'] # 只返回模型新生成的部分,通常它在prompt之后 result = generated_text[len(prompt):].strip() return result except Exception as e: print(f"模型调用出错: {e}") return None def clean_text(self, raw_text): """智能清洗文本:去除无关信息,保留核心正文""" prompt = f"""请清洗以下文本,只保留核心的、连贯的正文内容,去除所有广告、导航链接、版权声明、无关的页眉页脚、重复的标题和无关的符号。 原始文本: {raw_text} 清洗后的核心正文:""" return self._call_model(prompt) def extract_info(self, clean_text, info_type="general"): """从清洗后的文本中提取结构化信息""" if info_type == "product": prompt_template = """请从以下产品介绍文本中,提取关键信息并以JSON格式返回。需要的字段包括:产品名称、主要特点(列表形式)、参考价格、适用人群。 文本: {text} 提取的JSON信息:""" elif info_type == "news": prompt_template = """请从以下新闻文本中,提取关键信息并以JSON格式返回。需要的字段包括:事件标题、发生时间、发生地点、核心人物/组织、事件概要。 文本: {text} 提取的JSON信息:""" else: # general prompt_template = """请从以下文本中,提取最关键的信息点,以清晰的要点形式列出。 文本: {text} 关键信息点:""" prompt = prompt_template.format(text=clean_text) result = self._call_model(prompt) # 这里可以添加简单的JSON解析,如果返回的是JSON字符串的话 return result def generate_summary(self, clean_text, max_length=100): """为文本生成简洁摘要""" prompt = f"""请为以下文本生成一个简洁的摘要,摘要长度控制在{max_length}字以内。 文本: {clean_text} 摘要:""" return self._call_model(prompt) # 初始化处理器 processor = SmartDataProcessor(pipe)这个SmartDataProcessor类就是我们爬虫的“智能大脑”。它提供了三个方法:clean_text负责清洗,extract_info负责提取,generate_summary负责做摘要。每个方法都是构造一个特定的提示词(prompt)给模型,然后解析返回的结果。
4. 实战:爬虫与模型对接的完整示例
光说不练假把式,我们来看一个完整的例子。假设我们要爬取某个技术博客的文章,并进行智能处理。
4.1 第一步:编写爬虫抓取原始内容
我们用最简单的requests加BeautifulSoup来抓取和解析。
import requests from bs4 import BeautifulSoup import time def fetch_article(url): """抓取指定URL的文章原始HTML""" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } try: response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() # 检查请求是否成功 response.encoding = response.apparent_encoding return response.text except requests.RequestException as e: print(f"抓取 {url} 失败: {e}") return None def extract_raw_text(html_content): """从HTML中提取所有文本(初步清理)""" if not html_content: return "" soup = BeautifulSoup(html_content, 'html.parser') # 移除脚本、样式等不需要的标签 for script in soup(["script", "style", "nav", "footer", "aside", "header"]): script.decompose() # 获取所有文本 raw_text = soup.get_text(separator='\n', strip=True) # 简单的空白行清理 lines = [line.strip() for line in raw_text.splitlines() if line.strip()] return '\n'.join(lines) # 假设我们要爬取的博客文章链接 article_url = "https://example-tech-blog.com/post/123" html = fetch_article(article_url) raw_text = extract_raw_text(html) print("=== 原始文本(前500字符)===") print(raw_text[:500]) print("...")这段代码做了两件事:把网页下载下来,然后用BeautifulSoup去掉HTML标签,拿到一个初步清理过的纯文本。但你可以看到,这个文本里可能还包含很多我们不需要的东西,比如“相关阅读”、“推荐文章”、“上一篇下一篇”之类的。
4.2 第二步:调用模型进行智能处理
现在,我们把上一步得到的raw_text交给模型来处理。
# 假设processor已经按照上一节的代码初始化好了 if raw_text: print("\n=== 开始智能处理 ===") # 1. 智能清洗 print("正在清洗文本...") clean_text = processor.clean_text(raw_text) print("清洗完成,长度从", len(raw_text), "字符缩减到", len(clean_text) if clean_text else 0, "字符") print("\n--- 清洗后正文(前200字)---") print(clean_text[:200] if clean_text else "清洗失败") # 2. 提取关键信息 if clean_text: print("\n正在提取关键信息...") key_info = processor.extract_info(clean_text, info_type="general") print("--- 提取的关键信息 ---") print(key_info) # 3. 生成摘要 print("\n正在生成摘要...") summary = processor.generate_summary(clean_text, max_length=80) print("--- 生成的摘要 ---") print(summary) # 这里可以将 clean_text, key_info, summary 保存到数据库或文件 # 例如保存为JSON import json result = { "url": article_url, "clean_content": clean_text, "key_information": key_info, "summary": summary, "processed_at": time.strftime("%Y-%m-%d %H:%M:%S") } with open(f"processed_{article_url.split('/')[-1]}.json", 'w', encoding='utf-8') as f: json.dump(result, f, ensure_ascii=False, indent=2) print(f"\n处理结果已保存为JSON文件。")运行这段代码,你会看到模型依次完成了清洗、提取和摘要的工作。原本杂乱无章的文本,变成了干净的正文、结构化的信息点和一句简洁的概要。整个过程基本自动化,你只需要提供一个URL。
4.3 第三步:整合到Scrapy爬虫框架中
如果你用的是更专业的Scrapy框架,整合起来也很方便。主要是在爬虫的parse方法里,对提取到的文本数据调用我们的模型处理器。
# 这是一个简化的Scrapy Spider示例 import scrapy import json class TechBlogSpider(scrapy.Spider): name = 'tech_blog' start_urls = ['https://example-tech-blog.com/archive'] # 假设processor在别处初始化,并通过from_crawler方法传入 def __init__(self, processor=None, *args, **kwargs): super().__init__(*args, **kwargs) self.processor = processor def parse(self, response): # 1. 解析列表页,获取文章详情页链接 article_links = response.css('h2.entry-title a::attr(href)').getall() for link in article_links: yield response.follow(link, callback=self.parse_article) # 翻页逻辑(如果有) next_page = response.css('a.next-page::attr(href)').get() if next_page: yield response.follow(next_page, callback=self.parse) def parse_article(self, response): # 2. 解析详情页,获取原始文本 raw_html = response.body.decode('utf-8') # 这里可以复用之前的 extract_raw_text 函数逻辑,或者用Scrapy选择器 # 简单示例:获取所有段落文本 raw_text = ' '.join(response.css('article p::text').getall()) # 3. 调用智能处理器 if raw_text and self.processor: clean_text = self.processor.clean_text(raw_text) if clean_text: key_info = self.processor.extract_info(clean_text, info_type="news") summary = self.processor.generate_summary(clean_text) # 4. 构造Item item = { 'url': response.url, 'title': response.css('h1.entry-title::text').get(), 'clean_content': clean_text, 'key_information': key_info, 'summary': summary, 'published_date': response.css('time.entry-date::attr(datetime)').get() } yield item在Scrapy的settings.py里,你可以配置并启动这个模型处理器,然后把它作为参数传递给爬虫。这样,每爬取到一篇文章,都会自动进行智能后处理,产出的数据直接就是清洗和摘要后的高质量数据。
5. 处理效果与优化建议
在实际使用中,Qwen1.5-1.8B GPTQ模型对于常见的新闻、博客、论坛帖子等文本的清洗和摘要效果,已经相当可用。它能比较准确地识别并剔除侧边栏、评论框、广告推荐等无关内容,保留下连贯的正文。
对于信息提取,如果你在提示词里明确要求了JSON格式和字段,它也能给出一个大致可用的结构。当然,由于这是一个1.8B的“小模型”,不是那种动辄上百B参数的巨无霸,所以它的理解深度和复杂推理能力是有限的。别指望它像人一样完美地理解一篇高度专业或充满隐喻的文学评论。
这里有一些提升效果和效率的实用建议:
提示词(Prompt)是关键。模型的表现很大程度上取决于你怎么“问”它。给清洗任务时,把“核心正文”描述得越具体越好。比如,你可以举例说明什么是需要保留的,什么是需要删除的。对于提取任务,明确输出格式(如JSON)和所需字段,模型会更听话。
对长文本进行分段处理。模型有上下文长度限制。如果你抓取的是非常长的文章(比如上万字),直接塞给模型可能会被截断。一个实用的办法是,先用规则或简单算法(如查找“引言”、“第一章”等标题)把文章分成几个逻辑段落,然后分段处理,或者只把开头、结尾和中间关键段落送给模型做摘要。
后处理校验不可少。模型输出可能包含多余的标记、不完整的句子或不标准的JSON。写一些简单的后处理函数来清理这些输出是很有必要的。比如,用json.loads()尝试解析提取的信息,如果失败,可以尝试修复或记录错误。
考虑异步和批处理。模型推理相比网络请求是慢的。如果你的爬虫速度很快,可以考虑异步调用模型API,或者将爬取到的原始文本先存起来,然后另起一个进程或脚本进行批量的智能处理,避免爬虫被模型处理速度拖累。
缓存机制。如果多个页面有大量重复的模板文本(比如相同的导航栏、页脚),可以识别并缓存对这些内容的清洗结果,避免重复调用模型,节省资源。
6. 总结
回过头来看,把Qwen1.5-1.8B这类轻量级大模型和Python爬虫结合起来,思路其实很直接,但带来的效率提升是实实在在的。它把我们从繁琐、重复且脆弱的规则清洗工作中解放了出来,让爬虫的终点不再是“一堆待整理的原材料”,而是“立即可用的结构化信息”。
这套方案特别适合那些需要从大量同质化网页(如新闻站、博客平台、产品列表)中提取核心内容的场景。你不需要为每个网站精心编写和维护一套解析规则,只需要一个训练好的模型和精心设计的提示词,就能处理一大批网站。
当然,它也不是万能的。对于极端复杂的页面布局、或者对信息提取精度要求达到100%的场景,可能还是需要结合一些传统的规则方法。但对于大多数日常的数据采集和预处理需求,这个“爬虫+模型”的管道已经足够强大,能帮你省下大量时间。
如果你之前一直被数据清洗问题困扰,不妨试试这个方案。从一个小项目开始,比如先处理一个你常看的博客,看看效果。模型部署和调优的过程本身,也是一种宝贵的学习体验。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
