使用Scrapy爬取网站邮箱时遇请求错误,修改后仍未解决
解决Scrapy邮箱爬取器的URL错误及其他问题
核心问题分析
你遇到的Missing scheme in request url错误根源是启动URL缺少http/https协议头,同时代码还存在其他几处语法/逻辑问题,导致爬虫无法正常运行。
修正后的完整代码
import scrapy from scrapy.crawler import CrawlerProcess from scrapy.linkextractors.lxmlhtml import LxmlLinkExtractor from email_validator import validate_email, EmailNotValidError import pandas as pd import re from urllib.parse import urlparse, urlunparse # 修正启动URL,添加协议头 lista_star = ['https://vitalebarberiscanonico.it'] class MailSpider(scrapy.Spider): name = 'email' # 定义需要排除的链接关键词(根据需求调整) reject = ['facebook.com', 'twitter.com', 'instagram.com'] # 使用实例变量存储数据,避免类变量的线程安全问题 def __init__(self): self.data = [] def parse(self, response): links = LxmlLinkExtractor(allow=()).extract_links(response) links = [str(link.url) for link in links] # 避免重复处理当前页面URL if str(response.url) not in links: links.append(str(response.url)) for link in links: parsed_url = urlparse(link) # 补全协议头 if not parsed_url.scheme: link = urlunparse(parsed_url._replace(scheme='https')) # 只保留http/https协议的链接 elif parsed_url.scheme not in ['http', 'https']: continue # 跳过包含排除关键词的链接 if any(word in link for word in self.reject): continue try: yield scrapy.Request(url=link, callback=self.parse_link) except Exception as e: self.logger.error(f"请求链接失败: {link}, 错误: {str(e)}") def parse_link(self, response): html_text = str(response.text) # 使用更精准的邮箱正则表达式,支持带点的用户名和多级域名 mail_pattern = r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' mail_list = re.findall(mail_pattern, html_text) for email in mail_list: # 可选:用email_validator验证邮箱有效性 try: validate_email(email) self.data.append({'email': email, 'link': str(response.url)}) except EmailNotValidError: continue # 把get_info改为独立函数,避免类内执行顺序问题 def get_info(): process = CrawlerProcess({ 'USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' }) process.crawl(MailSpider, start_urls=lista_star) process.start() # 从爬虫实例中获取数据(单爬虫场景下的简化处理) spider = next(iter(process.crawlers)).spider df = pd.DataFrame(spider.data) df = df.drop_duplicates(subset='email') df = df.reset_index(drop=True) return df df = get_info() # 可选:保存结果到CSV df.to_csv('emails.csv', index=False) print(df)
关键修改点说明
- 补全启动URL的协议头:直接在
lista_star中添加https://,从根源解决启动时的URL scheme缺失问题。 - 定义
self.reject变量:添加常见社交平台的排除关键词,避免爬虫爬取无关链接,可根据需求调整。 - 导入缺失的模块:添加
re和urllib.parse模块,解决未导入导致的语法错误。 - 用实例变量存储数据:将
data从类变量改为__init__中的实例变量,避免多线程环境下的数据冲突。 - 优化链接处理逻辑:
- 补全无协议头的链接为https
- 跳过非http/https协议的链接
- 提前过滤包含排除关键词的链接,减少无效请求
- 改进邮箱正则表达式:使用更精准的正则,支持带点的用户名(如
john.doe@example.com)和多级域名(如info@example.co.uk)。 - 添加邮箱有效性验证:利用
email_validator过滤无效邮箱,避免存储错误格式的地址。 - 调整
get_info函数位置:改为独立函数,避免类定义未完成时调用方法的问题,同时调整数据获取方式,从爬虫实例中获取data。 - 优化异常处理:替换裸
except为捕获具体异常,并添加日志记录,方便排查问题。
内容的提问来源于stack exchange,提问作者Pren Ven
相关产品推荐
相关产品推荐

