Python3中使用BeautifulSoup构建比特币论坛爬虫的正确方法
完善比特币论坛主题帖子爬虫
嘿,我来帮你补全这个针对Bitcointalk论坛主题的爬虫代码!你已经搭好了基础的请求框架,接下来咱们把所有需要的字段爬取逻辑加上,还能自动遍历主题下的所有页面。
完整代码实现
import requests from bs4 import BeautifulSoup import re import time # 自定义请求头,避免被反爬拦截 HEADERS = { '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' } def get_html(url): try: # 添加延迟,减轻服务器压力 time.sleep(2) r = requests.get(url, headers=HEADERS) r.raise_for_status() # 检查请求是否成功 r.encoding = 'utf-8' return r.text except requests.exceptions.RequestException as e: print(f"请求出错: {e}") return None def parse_posts(html): if not html: return [] soup = BeautifulSoup(html, 'html.parser') posts = [] # 遍历所有帖子容器 post_wrappers = soup.find_all('div', class_='post_wrapper') for wrapper in post_wrappers: post_data = {} # 1. 用户名 username_elem = wrapper.find('a', class_='bbc_username') post_data['username'] = username_elem.text.strip() if username_elem else '匿名用户' # 2. 用户状态(在线/离线) status_elem = wrapper.find('span', class_=['online', 'offline']) post_data['status'] = status_elem['title'].strip() if status_elem else '未知状态' # 3. 发帖日期时间 posttime_elem = wrapper.find('div', class_='posttime') # 取title里的绝对时间,避免相对时间(比如"今天10:00") post_data['post_datetime'] = posttime_elem.find('span')['title'].strip() if posttime_elem and posttime_elem.find('span') else '未知时间' # 4. 帖子内容(处理HTML转纯文本) content_elem = wrapper.find('div', class_='post', id=re.compile(r'msg_\d+')) post_data['content'] = content_elem.get_text(strip=True, separator='\n') if content_elem else '无内容' # 5. 活跃度(Activity)和Merit值 poster_info = wrapper.find('dl', class_='poster_info') if poster_info: # 遍历所有dt-dd对,匹配需要的字段 dt_elements = poster_info.find_all('dt') dd_elements = poster_info.find_all('dd') for dt, dd in zip(dt_elements, dd_elements): dt_text = dt.text.strip() if dt_text == 'Activity:': post_data['activity'] = dd.text.strip() elif dt_text == 'Merit:': post_data['merit'] = dd.text.strip() # 处理缺失字段 post_data.setdefault('activity', '0') post_data.setdefault('merit', '0') else: post_data['activity'] = '0' post_data['merit'] = '0' posts.append(post_data) return posts def get_next_page_url(html): if not html: return None soup = BeautifulSoup(html, 'html.parser') # 找到下一页链接(页面底部的"Next"按钮) next_link = soup.find('a', text='Next') if next_link and 'href' in next_link.attrs: return 'https://bitcointalk.org/' + next_link['href'] return None def crawl_topic(start_url): current_url = start_url all_posts = [] while current_url: print(f"正在爬取页面: {current_url}") html = get_html(current_url) if not html: break # 解析当前页面帖子 page_posts = parse_posts(html) all_posts.extend(page_posts) # 获取下一页链接 current_url = get_next_page_url(html) print(f"爬取完成,共获取{len(all_posts)}条帖子") return all_posts # 主程序入口 if __name__ == '__main__': start_url = 'https://bitcointalk.org/index.php?topic=2056041.0' all_posts = crawl_topic(start_url) # 可以在这里添加保存数据的逻辑,比如存到CSV或者JSON # 示例:保存到JSON文件 import json with open('bitcointalk_posts.json', 'w', encoding='utf-8') as f: json.dump(all_posts, f, ensure_ascii=False, indent=4) print("数据已保存到bitcointalk_posts.json")
代码说明
- 请求头与延迟:添加了
User-Agent模拟浏览器请求,同时每次请求间隔2秒,避免触发论坛的反爬机制。 - 字段解析逻辑:
- 用户名:定位到
bbc_username类的链接元素 - 用户状态:通过
online/offline类的span标签获取状态描述 - 发帖时间:使用span标签的
title属性获取绝对时间,避免相对时间的歧义 - 帖子内容:提取
post容器内的纯文本,保留换行结构 - 活跃度与Merit:遍历用户信息的dt-dd对,匹配对应字段,缺失时默认赋值为0
- 用户名:定位到
- 分页处理:通过页面底部的"Next"按钮链接自动获取下一页地址,直到没有下一页为止
- 数据保存:示例中将爬取到的所有帖子保存为JSON文件,方便后续分析
注意事项
- 论坛可能会有反爬机制,如果遇到请求被拦截,可以尝试更换
User-Agent或者增加请求延迟 - 部分用户可能没有填写活跃度或Merit值,代码已经做了空值处理
- 大量爬取前建议先查看论坛的规则,确保合规
内容的提问来源于stack exchange,提问作者egorkh
相关产品推荐
相关产品推荐

