Python爬虫:从CSV读URL爬取电话邮编导出CSV的代码报错排查
爬取URL列表提取联系方式代码修正方案
现有代码存在的核心问题
- 多套网络请求逻辑混用:同时引入Scrapy、urllib、requests三个库的请求能力,既没有正确继承Scrapy的Spider基类实现爬虫流程,也没有统一用单套逻辑发请求,类定义外的导出代码会在爬虫未启动时直接执行,根本拿不到爬取结果
- 变量未定义/错用:parse方法中获取了
response.body赋值给s,传给BeautifulSoup的却是未声明的html变量;循环内使用row[1]['URL']但从未定义row变量;读取到的页面内容是bytes类型,直接传入正则匹配会触发类型错误;邮编匹配成功时数据存入mail_1列表,最终导出却读取zipcode_1列表,匹配到的邮编会全部丢失 - 流程逻辑错误:
start_urls是URL列表,直接传给单个Request对象会触发参数错误;创建空的DataFramedf2做遍历,循环体根本不会执行,等于所有提取逻辑完全不生效;Scrapy爬虫入口方法名应为start_requests(复数),现有写法框架不会识别启动 - 异常与配置错误:捕获HTTPError时引用了未导入的urllib3库;SSL配置使用已被主流站点废弃的SSLv23协议,会触发握手失败;请求失败分支里直接读取未赋值的
url_name变量,会触发二次报错 - 冗余代码过多:重复导入BeautifulSoup、urlparse;导入的numpy、Scrapy全量组件完全没有被使用;最后CSV转JSON的逻辑只写了一半没有落地
精简可运行版本(适合初学者,无多余依赖)
依赖安装
先执行命令安装需要的库:
pip install pandas requests
完整代码
import re import ssl import pandas as pd import requests from requests.adapters import HTTPAdapter from urllib3.util.ssl_ import create_urllib3_context # 初始化存储列表 phn_list = [] zipcode_list = [] # 配置请求头,模拟浏览器 HEADERS = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' } # 适配老旧SSL站点,避免证书报错 class LegacySSLAdapter(HTTPAdapter): def init_poolmanager(self, *args, **kwargs): ctx = create_urllib3_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE kwargs['ssl_context'] = ctx return super().init_poolmanager(*args, **kwargs) # 读取urls.csv里的所有URL,URL每行一个即可,无需表头 df_urls = pd.read_csv('urls.csv', header=None) url_list = df_urls[0].dropna().str.strip().tolist() # 创建请求会话 session = requests.Session() session.mount('https://', LegacySSLAdapter()) # 正则匹配规则 phone_pattern = re.compile(r'\d{3}-\d{3}-\d{4}') zip_pattern = re.compile(r'(?<=, [A-Z]{2} )\d{5}') # 逐个遍历URL爬取 for url in url_list: # 补全缺失http头的URL if not url.startswith(('http://', 'https://')): url = 'https://' + url current_url = url try: resp = session.get(url, headers=HEADERS, timeout=15, verify=False) resp.encoding = resp.apparent_encoding page_text = resp.text current_url = resp.url # 提取电话号码 phones = phone_pattern.findall(page_text) phones = list(set(phones)) # 结果去重 if not phones: phn_list.append((current_url, "No phone number found.")) else: for phone in phones: phn_list.append((current_url, phone)) # 提取邮编 zipcodes = zip_pattern.findall(page_text) zipcodes = list(set(zipcodes)) # 结果去重 if not zipcodes: zipcode_list.append((current_url, "No zipcode address found.")) else: for zipcode in zipcodes: zipcode_list.append((current_url, zipcode)) print(f"Finish crawl: {current_url}") except Exception as e: err_msg = f"Crawl failed: {str(e)}" phn_list.append((current_url, err_msg)) zipcode_list.append((current_url, err_msg)) print(f"Fail crawl {current_url}: {str(e)}") # 生成结果DataFrame df_phone = pd.DataFrame(phn_list, columns=['URL', 'Phone_No']).drop_duplicates(subset=['URL', 'Phone_No'], keep='first') df_zip = pd.DataFrame(zipcode_list, columns=['URL', 'Zipcode']).drop_duplicates(subset=['URL', 'Zipcode'], keep='first') # 合并结果并导出CSV df_final = pd.merge(df_phone, df_zip, on='URL', how='outer') df_final.to_csv('result_contact.csv', index=False, encoding='utf-8-sig') print("Result saved to result_contact.csv") # 导出JSON格式结果 df_final.to_json('result_contact.json', orient='records', force_ascii=False, indent=2)
使用说明
- 把待爬取的URL存在同目录下的
urls.csv文件里,每行一个URL即可,不需要设置表头 - 爬取结果会自动存在同目录下的
result_contact.csv,同时生成JSON格式结果 - 代码自动处理了无http头的URL、SSL证书报错、请求超时、重复数据去重问题,导出的CSV用Excel打开不会乱码
内容的提问来源于stack exchange,提问作者user19233490
相关产品推荐
相关产品推荐

