网站爬虫与数据采集怎么做?(保姆级教程)
2026/7/3 4:47:28 网站建设 项目流程

想把几千个网站分好类、评好分,光靠人工登记肯定不现实,必须靠爬虫自动抓取关键信息。

比如一些导航网站收录了大量设计、产品、开发类的优质站点。你有没想过,这类导航站是怎么知道某个新网站“长什么样”的?

答案就是:一套自动化的爬虫与数据采集流水线在默默地干活。

今天这篇文章,手把手教你从零搭建网站爬虫与数据采集系统。读完你可以直接落地自己的采集项目。


一、在开始写代码前,先搞懂边界

做爬虫的底线就一句话:只采公开数据,尊重 robots.txt,不要对目标服务器造成压力。

我们模拟的场景是:你发现了一批优质网站,想把它们的标题、描述、截图、关键词等信息采下来这是在帮助内容曝光,属于正常的数据采集。

正式开始前,每条请求都遵守三个原则:

  • User-Agent 写清楚自己是谁(留联系方式)

  • 请求间隔至少 1-3 秒

  • 遇到 403 或反爬,果断停手或走正规 API


二、最简爬虫:30 行代码抓取一个网页的基本信息

先从最简单的单页面抓取开始。假设我们要采集一个设计工具网站的标题和 Meta 描述。

python

import requests from bs4 import BeautifulSoup import time # 尊重对方,写明身份 headers = { 'User-Agent': 'Mozilla/5.0 (compatible; DataCollectBot/1.0; +https://example.com/bot)' } url = 'https://example-design-tool.com' try: resp = requests.get(url, headers=headers, timeout=10) resp.raise_for_status() resp.encoding = resp.apparent_encoding # 自动检测编码,防乱码 soup = BeautifulSoup(resp.text, 'html.parser') # 提取标题 title = soup.title.string.strip() if soup.title else '' # 提取 Meta 描述 desc_tag = soup.find('meta', attrs={'name': 'description'}) description = desc_tag['content'].strip() if desc_tag else '' # 提取关键词 keywords_tag = soup.find('meta', attrs={'name': 'keywords'}) keywords = keywords_tag['content'].strip() if keywords_tag else '' print(f'标题: {title}') print(f'描述: {description}') print(f'关键词: {keywords}') except Exception as e: print(f'抓取失败: {e}')

这么一段代码,就完成了一次基础采集。


三、导航站标配:批量抓取 + 自动分类

通常是一次性处理几百上千个 URL。我们用异步 IO 来提速,同时对采集到的内容做一个简单的自动分类。

1. 异步批量抓取(asyncio + aiohttp)

python

import asyncio import aiohttp from bs4 import BeautifulSoup async def fetch_site(session, url, semaphore): async with semaphore: # 控制并发,别把对方打挂了 try: async with session.get(url, timeout=15) as resp: html = await resp.text() soup = BeautifulSoup(html, 'html.parser') title = soup.title.string.strip() if soup.title else '' desc_tag = soup.find('meta', attrs={'name': 'description'}) desc = desc_tag['content'].strip() if desc_tag else '' return { 'url': url, 'title': title, 'description': desc, 'status': resp.status } except Exception as e: return {'url': url, 'error': str(e), 'status': 0} async def batch_fetch(urls, concurrency=10): semaphore = asyncio.Semaphore(concurrency) async with aiohttp.ClientSession( headers={'User-Agent': 'DataCollectBot/1.0'} ) as session: tasks = [fetch_site(session, url, semaphore) for url in urls] results = await asyncio.gather(*tasks) return results # 使用示例 urls = [ 'https://site-a.com', 'https://site-b.com', 'https://site-c.com', ] results = asyncio.run(batch_fetch(urls, concurrency=10))

这样一来,200 个网站大概 30 秒就能采完基本信息。

2. 基于规则的自动分类

拿到标题和描述后,我们可以用关键字匹配给网站打分类标签。

CATEGORY_RULES = { '设计资源': ['图标', 'icon', '素材', '配色', '字体', 'mockup', 'sketch', 'figma'], '前端开发': ['react', 'vue', 'css', 'javascript', '组件库', '框架', '前端'], '效率工具': ['在线工具', '转换', '生成器', '压缩', '格式', '截图', '录屏'], '产品灵感': ['灵感', '参考', '案例', 'behance', 'dribbble', 'landing page'], '开源项目': ['github', '开源', 'open source', 'repo'], } def classify_site(title, description): text = (title + ' ' + description).lower() for cat, keywords in CATEGORY_RULES.items(): if any(kw in text for kw in keywords): return cat return '其他'

这个分类器虽然简单,但准确率能做到 80% 以上。剩下的 20% 复杂情况,完全可以交给运营人工修正,效率已经大大提升。


四、进阶:全站整页抓取 + 动态渲染

有时候目标网站是纯前端渲染的(React/Vue 做的 SPA),requests 只能拿到一个空壳。这时就要用 Playwright 模拟真实浏览器。

from playwright.sync_api import sync_playwright def crawl_spa_with_playwright(url): with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page() page.goto(url, wait_until='networkidle') # 等网络请求全部完成 html = page.content() browser.close() soup = BeautifulSoup(html, 'html.parser') # sites = [] for card in soup.select('.site-card'): # 具体的 class 名根据实际情况调整 sites.append({ 'name': card.select_one('.site-name').text.strip(), 'url': card.select_one('.site-url')['href'], 'desc': card.select_one('.site-desc').text.strip(), }) return sites

别滥用——只在自己需要的少数场景下开浏览器,并发控制到 2-3 个,不然内存和对方的服务器都扛不住。


五、整站爬取实战:带翻页的全量数据采集

自动翻页 + 去重 + 断点续爬

import hashlib visited_urls = set() def crawl_all_pages(base_url, max_pages=50): results = [] for page_num in range(1, max_pages + 1): url = f'{base_url}?page={page_num}' print(f'正在采集第 {page_num} 页...') # 这里用刚才写的 fetch_site 或 Playwright page_results = fetch_page_data(url) if not page_results: print('没有更多内容,翻页结束') break for item in page_results: # 用 URL 做去重 fingerprint = hashlib.md5(item['url'].encode()).hexdigest() if fingerprint not in visited_urls: visited_urls.add(fingerprint) results.append(item) time.sleep(2) # 礼貌等待 return results

注意:整站爬取要格外谨慎,控制频率,只采一次用于离线分析,不要持续高频抓取。


六、反爬与应对:那些你一定要知道的“潜规则”

做多了你就发现,不是所有网站都开大门欢迎你。常见反爬及应对策略:

反爬手段表现应对方式
封 IP连续请求后 403换 IP 代理池、降低频率、加随机延迟
UA 检测requests 默认 UA 直接 403换成正常浏览器 UA,最好也加上 Accept-Language
Cookie 验证不带 Cookie 拿不到数据先访问首页拿 Cookie,再带 Cookie 请求数据页
前端混淆数据用 JS 加密Playwright 直接取渲染后 DOM,或者逆向 JS(高成本)
验证码滑块/图形验证码到这个地步就停手吧,换个数据源

在采集收录的设计资源站时,我就遇到过:有些国外设计站对爬虫特别敏感,直接封数据中心 IP。解决方案很简单——切到住宅代理,并且把每次请求间隔拉到 5 秒以上。


七、数据存储与清洗:让采集到的数据真正可用

采回来的原始数据必然是脏的,标题带\n、描述是空、URL 少了协议头……必须清洗。

import re def clean_site_data(raw_item): title = raw_item.get('title', '') # 去除多余空白符 title = re.sub(r'\s+', ' ', title).strip() # 截断过长标题 if len(title) > 100: title = title[:97] + '...' url = raw_item.get('url', '') # 补全协议头 if url.startswith('//'): url = 'https:' + url elif not url.startswith('http'): url = 'https://' + url desc = raw_item.get('description', '') desc = re.sub(r'\s+', ' ', desc).strip()[:300] return { 'url': url, 'title': title, 'description': desc, 'category': raw_item.get('category', '其他'), 'crawl_time': raw_item.get('crawl_time', '') }

清洗完成后写入 CSV 或数据库,这套数据就可以直接喂给后台导入接口了。


八、从采集到上线

假设我们现在采集了 500 个优质设计类网站,完整流程是:

  1. 收集种子 URL:从 GitHub Awesome List、Product Hunt、设计师推特等渠道获取候选列表。

  2. 批量爬取信息:用 asyncio 异步抓标题、描述、关键词。

  3. 自动分类 + 去重:规则匹配分类,URL 指纹去重。

  4. 质量过滤:标题为空或描述太短的低质量站点直接丢弃。

  5. 人工抽检:随机抽 20 个验证分类和描述是否靠谱。

  6. 提交:通过提交入口或者直接联系运营一次性导入。

这套流水线跑通后,一个人的效率抵得上一个编辑团队。之所以能维持高频更新、分类准确,背后大概率也是类似的自动化采集流程在运转。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询