目标网址
输入要抓取的网页URL
抓取设置
配置抓取参数
只抓取匹配选择器的内容
什么是网页爬虫?
网页爬虫(Web Spider)是一种自动抓取互联网信息的程序,通过模拟浏览器请求获取网页内容,然后解析提取所需数据。爬虫广泛应用于搜索引擎索引、数据分析、竞品监控、价格比较、内容聚合等领域。
网页爬虫的基本原理
- 发送请求:向目标网站发送HTTP请求,获取HTML内容
- 解析页面:使用HTML解析器解析返回的HTML文档
- 提取数据:使用选择器或正则表达式提取所需数据
- 存储数据:将提取的数据保存到数据库或文件中
- 继续爬取:根据链接规则继续爬取其他页面
爬虫的分类
| 类型 | 特点 | 常用技术 |
|---|---|---|
| 静态爬虫 | 抓取静态HTML页面 | Python + BeautifulSoup, Node.js + Cheerio |
| 动态爬虫 | 执行JavaScript,抓取动态内容 | Puppeteer, Selenium, Playwright |
| API爬虫 | 直接调用API接口获取数据 | REST API, GraphQL |
| 分布式爬虫 | 多节点协作爬取,大规模数据 | Scrapy Cluster, Celery |
常用爬虫框架
- Python:Scrapy(功能强大)、BeautifulSoup(简单易用)、Requests + BeautifulSoup
- Node.js:Puppeteer(支持动态页面)、Cheerio(类似jQuery)、Axios
- Java:Jsoup(HTML解析)、HttpClient(HTTP请求)、WebMagic
- Go:Colly(高性能爬虫框架)、net/http(标准库)
常见问题(FAQ)
Q: 网页爬虫合法吗?
A: 爬虫本身是合法的技术,但需要注意:1)遵守网站的robots.txt规定;2)不要对服务器造成过大压力;3)不要抓取有版权保护的内容;4)尊重用户隐私和敏感信息;5)遵守相关法律法规。
Q: 如何避免被封禁?
A: 避免被封禁的方法:1)设置合理的请求间隔(如1-3秒);2)使用代理IP池轮换;3)随机更换User-Agent;4)遵守robots.txt规则;5)控制并发请求数量;6)使用cookies维持会话。
Q: 如何处理动态网页?
A>动态网页需要使用浏览器自动化工具:1)Puppeteer(推荐,Node.js);2)Selenium(支持多语言);3)Playwright(微软开发);4)PhantomJS(已停止维护)。这些工具可以执行JavaScript并获取渲染后的页面内容。
Q: 什么是robots.txt?
A>robots.txt是网站根目录下的文本文件,告诉爬虫哪些页面可以抓取,哪些不可以。遵守robots.txt是爬虫的基本礼仪。可以使用爬虫框架内置的RobotsTxtParser来自动解析和遵守这些规则。
代码示例
JavaScript Fetch 抓取示例
// 使用 Fetch API 抓取网页内容
async function crawlWebPage(url) {
try {
const response = await fetch(url, {
method: 'GET',
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
// 提取标题
const title = doc.querySelector('title')?.textContent || '';
// 提取所有链接
const links = Array.from(doc.querySelectorAll('a[href]')).map(a => ({
text: a.textContent.trim(),
href: a.href
}));
// 提取所有图片
const images = Array.from(doc.querySelectorAll('img[src]')).map(img => ({
alt: img.alt || '',
src: img.src
}));
// 提取Meta信息
const meta = {};
doc.querySelectorAll('meta').forEach(m => {
if (m.name) meta[m.name] = m.content;
if (m.property) meta[m.property] = m.content;
});
// 提取页面文本
const text = doc.body?.textContent || '';
return { title, links, images, meta, text };
} catch (error) {
console.error('抓取失败:', error);
return null;
}
}
// 使用示例
crawlWebPage('https://example.com').then(data => {
if (data) {
console.log('页面标题:', data.title);
console.log('链接数量:', data.links.length);
console.log('图片数量:', data.images.length);
console.log('Meta信息:', data.meta);
}
});
Python Requests + BeautifulSoup
import requests
from bs4 import BeautifulSoup
import json
import csv
def crawl_webpage(url, selector=None):
"""
爬取网页内容
:param url: 目标网址
:param selector: CSS选择器(可选)
:return: 包含网页数据的字典
"""
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
}
try:
# 发送请求
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
response.encoding = response.apparent_encoding
# 解析HTML
soup = BeautifulSoup(response.text, 'html.parser')
# 如果指定了选择器,只提取该部分
if selector:
soup = soup.select_one(selector)
if not soup:
return {'error': '未找到匹配选择器的内容'}
# 提取标题
title = soup.find('title').get_text(strip=True) if soup.find('title') else ''
# 提取所有链接
links = []
for a in soup.find_all('a', href=True):
links.append({
'text': a.get_text(strip=True),
'href': a['href']
})
# 提取所有图片
images = []
for img in soup.find_all('img', src=True):
images.append({
'alt': img.get('alt', ''),
'src': img['src']
})
# 提取Meta信息
meta = {}
for m in soup.find_all('meta'):
name = m.get('name') or m.get('property')
content = m.get('content')
if name and content:
meta[name] = content
# 提取页面文本
text = soup.get_text(strip=True, separator='\n')
return {
'title': title,
'links': links,
'images': images,
'meta': meta,
'text': text
}
except Exception as e:
print(f'爬取失败: {e}')
return {'error': str(e)}
def export_to_json(data, filename):
"""导出为JSON格式"""
with open(filename, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def export_to_csv(data, filename):
"""导出为CSV格式"""
if 'links' in data:
with open(filename, 'w', encoding='utf-8', newline='') as f:
writer = csv.writer(f)
writer.writerow(['Text', 'URL'])
for link in data['links']:
writer.writerow([link['text'], link['href']])
# 使用示例
if __name__ == '__main__':
url = 'https://example.com'
data = crawl_webpage(url, selector='.content')
if data and 'error' not in data:
print(f'标题: {data["title"]}')
print(f'链接数: {len(data["links"])}')
print(f'图片数: {len(data["images"])}')
# 导出数据
export_to_json(data, 'output.json')
export_to_csv(data, 'links.csv')
else:
print('爬取失败:', data.get('error'))
Node.js Puppeteer 爬虫
const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');
async function crawlWebPage(url, options = {}) {
try {
// 启动浏览器
const browser = await puppeteer.launch({
headless: options.headless !== false,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
// 设置User-Agent
await page.setUserAgent(options.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)');
// 设置视口
await page.setViewport({ width: 1920, height: 1080 });
// 访问页面
await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
// 等待选择器(如果指定)
if (options.selector) {
await page.waitForSelector(options.selector, { timeout: 5000 });
}
// 执行JavaScript提取数据
const data = await page.evaluate((selector) => {
// 如果指定了选择器,只提取该部分
let root = document;
if (selector) {
const element = document.querySelector(selector);
if (element) root = element;
}
// 提取标题
const title = document.querySelector('title')?.textContent || '';
// 提取所有链接
const links = Array.from(root.querySelectorAll('a[href]')).map(a => ({
text: a.textContent.trim(),
href: a.href
}));
// 提取所有图片
const images = Array.from(root.querySelectorAll('img[src]')).map(img => ({
alt: img.alt || '',
src: img.src
}));
// 提取Meta信息
const meta = {};
document.querySelectorAll('meta').forEach(m => {
if (m.name) meta[m.name] = m.content;
if (m.property) meta[m.property] = m.content;
});
// 提取页面文本
const text = root.body?.textContent || '';
return { title, links, images, meta, text };
}, options.selector || '');
// 截图
if (options.screenshot) {
await page.screenshot({
path: options.screenshotPath || 'screenshot.png',
fullPage: true
});
}
await browser.close();
return data;
} catch (error) {
console.error('爬取失败:', error);
return null;
}
}
async function crawlMultiplePages(urls, concurrency = 3) {
// 并发爬取多个页面
const results = [];
const chunks = [];
// 分块处理
for (let i = 0; i < urls.length; i += concurrency) {
chunks.push(urls.slice(i, i + concurrency));
}
for (const chunk of chunks) {
const promises = chunk.map(url => crawlWebPage(url));
const chunkResults = await Promise.all(promises);
results.push(...chunkResults);
}
return results;
}
// 使用示例
async function main() {
const url = 'https://example.com';
const data = await crawlWebPage(url, {
selector: '.content',
screenshot: true,
screenshotPath: 'screenshot.png'
});
if (data) {
console.log('标题:', data.title);
console.log('链接数:', data.links.length);
console.log('图片数:', data.images.length);
// 保存为JSON
fs.writeFileSync('output.json', JSON.stringify(data, null, 2));
}
}
main();
Java Jsoup 爬虫
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class WebCrawler {
public static Map crawlWebPage(String url, String selector) {
Map result = new HashMap<>();
try {
// 连接并获取文档
Document doc = Jsoup.connect(url)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
.timeout(10000)
.get();
// 如果指定了选择器,只提取该部分
if (selector != null && !selector.isEmpty()) {
Element selected = doc.selectFirst(selector);
if (selected != null) {
doc = Jsoup.parse(selected.outerHtml());
}
}
// 提取标题
String title = doc.title();
result.put("title", title);
// 提取所有链接
List