Python批量爬取多网站:链接选择器失效,如何正确设置?
解决批量爬取网站帖子时选择器无效的问题
核心问题原因
不同网站的HTML结构差异极大,你用的a.post-link是针对特定网站结构写的选择器,绝大多数网站不会使用这个类名,所以无法匹配到内容。
怎么找到正确的选择器
手动分析单个网站:
打开目标网站,右键点击任意帖子标题/链接 → 检查元素,查看对应<a>标签的特征:- 查看标签的class属性,比如有的网站用
a.entry-link、a.post-title-link - 查看父级标签的结构,比如帖子可能包裹在
<article class="post-item">里,选择器可以写article.post-item > a - 用属性匹配,比如帖子链接通常包含
/post/或/article/,可以写a[href*="/post/"]
- 查看标签的class属性,比如有的网站用
通用兜底选择器(适合批量处理):
如果不想逐个网站分析,可以先尝试这些通用规则,覆盖大多数常见结构:- 匹配标题标签内的链接:
h2 > a, h3 > a, h4 > a(大多数帖子标题会放在h2/h3标签里) - 匹配带post相关类的父元素下的链接:
div.post > a, article.post > a - 过滤导航类链接后的所有有效链接:
a[href]:not([href*="home"]):not([href*="about"]):not([href*="contact"])
- 匹配标题标签内的链接:
改进后的代码方案
针对1000个网站的批量场景,需要支持自定义选择器+兜底逻辑,同时处理常见问题(相对链接、反爬、错误处理):
1. 导入依赖库
import requests from bs4 import BeautifulSoup import pandas as pd import time from urllib.parse import urljoin, urlparse
2. 优化爬取函数
def scrape_posts(url, link_selector, title_selector): all_posts = [] # 设置请求头,模拟浏览器访问 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' } try: response = requests.get(url, headers=headers, timeout=15) response.raise_for_status() # 捕获HTTP错误 soup = BeautifulSoup(response.content, 'html.parser') # 先尝试自定义选择器 post_elements = soup.select(link_selector) # 自定义选择器无效时,用兜底规则 if not post_elements: # 优先匹配标题标签内的链接 post_elements = soup.select('h2 > a, h3 > a, h4 > a') # 仍无结果则过滤导航链接 if not post_elements: exclude_keywords = ['home', 'about', 'contact', 'category', 'tag', 'archive'] post_elements = [ a for a in soup.select('a[href]') if not any(k in a['href'].lower() for k in exclude_keywords) ] for post_element in post_elements: # 处理相对链接,转为绝对链接 post_link = post_element.get('href', '') if post_link: post_link = urljoin(url, post_link) # 获取标题:先尝试自定义选择器,再用链接文本,最后用父元素文本 post_title = '' if title_selector: title_tag = post_element.select_one(title_selector) if title_tag: post_title = title_tag.get_text(strip=True) if not post_title: post_title = post_element.get_text(strip=True) # 只保留有有效链接和标题的条目 if post_link and post_title: all_posts.append({'link': post_link, 'title': post_title}) except Exception as e: print(f"爬取 {url} 失败: {str(e)}") return all_posts
3. 批量处理并保存Excel
假设你的网站列表DataFrame为df,包含website_url列,新增自定义选择器列后批量处理:
# 读取网站列表Excel df = pd.read_excel('websites_list.xlsx') # 新增自定义选择器列,设置默认值 df['link_selector'] = 'a.post-link' df['title_selector'] = 'h3.post-title' # 针对特殊网站修改选择器(示例) df.loc[df['website_url'] == 'https://example1.com', 'link_selector'] = 'article.post-item > a' df.loc[df['website_url'] == 'https://example1.com', 'title_selector'] = 'h2.entry-title' # 批量爬取并生成单个Excel文件 for _, row in df.iterrows(): url = row['website_url'] link_sel = row['link_selector'] title_sel = row['title_selector'] posts = scrape_posts(url, link_sel, title_sel) if posts: # 用网站域名作为文件名 domain = urlparse(url).netloc pd.DataFrame(posts).to_excel(f'{domain}_posts.xlsx', index=False) print(f"已保存 {domain} 的帖子数据") # 设置延迟,避免触发反爬 time.sleep(1)
额外注意事项
- 动态内容处理:如果网站用JS动态加载帖子(比如滚动加载),
requests无法获取到内容,需要用selenium或playwright渲染页面 - 反爬应对:如果出现频繁被封,可以增加延迟时间、使用代理IP池、随机更换User-Agent
- 数据去重:可以在爬取后对
post_link列去重,避免重复条目
内容的提问来源于stack exchange,提问作者Alexandru Mihalache
相关产品推荐
相关产品推荐

