Files
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

220 lines
6.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""
简化版网页抓取测试脚本
只测试InfoQ网站,避免过多请求
"""
import sys
import os
import sqlite3
import datetime
import time
import random
from urllib.parse import urljoin
import requests
from bs4 import BeautifulSoup
# 测试配置
TEST_CONFIG = {
'database_path': '/home/ubuntu/nanocode/it_automation_test/data/test_articles.db',
'base_dir': '/home/ubuntu/nanocode/it_automation_test',
'test_website': {
'name': 'InfoQ',
'url': 'https://www.infoq.com',
'category': 'tech'
},
'user_agents': [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
],
'request_delay': 3, # 更长的延迟,避免被封
'timeout': 30,
'max_articles': 5, # 只抓取5篇文章用于测试
}
def init_database():
"""初始化测试数据库"""
db_path = TEST_CONFIG['database_path']
os.makedirs(os.path.dirname(db_path), exist_ok=True)
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS test_articles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
url TEXT UNIQUE NOT NULL,
source TEXT NOT NULL,
category TEXT,
publish_date TEXT,
word_count INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
conn.commit()
conn.close()
print(f"✅ 测试数据库初始化完成: {db_path}")
def save_test_article(title, url, source, category):
"""保存测试文章"""
try:
conn = sqlite3.connect(TEST_CONFIG['database_path'])
cursor = conn.cursor()
cursor.execute('''
INSERT OR IGNORE INTO test_articles
(title, url, source, category, publish_date)
VALUES (?, ?, ?, ?, ?)
''', (title, url, source, category, datetime.datetime.now().strftime('%Y-%m-%d')))
conn.commit()
conn.close()
return True
except Exception as e:
print(f"❌ 保存文章失败: {e}")
return False
def fetch_with_retry(url, max_retries=2):
"""带重试的网页抓取"""
headers = {
'User-Agent': random.choice(TEST_CONFIG['user_agents']),
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
}
for attempt in range(max_retries):
try:
time.sleep(TEST_CONFIG['request_delay'])
print(f" 尝试抓取 ({attempt+1}/{max_retries}): {url[:60]}...")
response = requests.get(url, headers=headers, timeout=TEST_CONFIG['timeout'])
response.raise_for_status()
return response
except Exception as e:
if attempt == max_retries - 1:
print(f"❌ 抓取失败: {e}")
return None
time.sleep(2 ** attempt)
def extract_infoq_articles(html, base_url):
"""从InfoQ首页提取文章链接"""
articles = []
soup = BeautifulSoup(html, 'html.parser')
# InfoQ的文章通常在带有特定class的链接中
# 这里使用通用选择器,避免网站结构变化
article_links = []
# 尝试多种选择器
selectors = [
'a[href*="/news/"]',
'a[href*="/articles/"]',
'.card__title a',
'.article-card a',
'h2 a',
'h3 a'
]
for selector in selectors:
links = soup.select(selector)
if links:
article_links.extend(links)
break
# 去重
seen_urls = set()
for link in article_links:
if len(articles) >= TEST_CONFIG['max_articles']:
break
href = link.get('href', '')
title = link.get_text(strip=True)
if not href or not title or len(title) < 10:
continue
# 构建完整URL
if href.startswith('http'):
full_url = href
else:
full_url = urljoin(base_url, href)
# 去重
if full_url in seen_urls:
continue
seen_urls.add(full_url)
articles.append({
'title': title,
'url': full_url,
'source': TEST_CONFIG['test_website']['name'],
'category': TEST_CONFIG['test_website']['category'],
})
return articles
def main():
"""主测试函数"""
print("=" * 60)
print("🚀 开始网页抓取测试")
print("=" * 60)
print(f"📁 测试目录: {TEST_CONFIG['base_dir']}")
print(f"🗄️ 数据库: {TEST_CONFIG['database_path']}")
print(f"🌐 测试网站: {TEST_CONFIG['test_website']['name']}")
print(f"🔗 网站URL: {TEST_CONFIG['test_website']['url']}")
print("=" * 60)
# 初始化数据库
init_database()
# 抓取首页
site = TEST_CONFIG['test_website']
print(f"\n📡 抓取网站: {site['name']}")
response = fetch_with_retry(site['url'])
if not response:
print("❌ 无法抓取网站首页")
return 0
# 提取文章
articles = extract_infoq_articles(response.text, site['url'])
print(f"📰 找到 {len(articles)} 篇文章")
# 保存文章
saved_count = 0
for i, article in enumerate(articles, 1):
print(f" {i}. {article['title'][:50]}...")
if save_test_article(article['title'], article['url'],
article['source'], article['category']):
saved_count += 1
# 验证结果
print(f"\n✅ 测试完成,共保存 {saved_count} 篇文章")
# 显示保存的文章
if saved_count > 0:
print("\n📋 保存的文章列表:")
conn = sqlite3.connect(TEST_CONFIG['database_path'])
cursor = conn.cursor()
cursor.execute('SELECT title, url FROM test_articles ORDER BY id DESC LIMIT 5')
for row in cursor.fetchall():
print(f" • {row[0][:40]}...")
conn.close()
return saved_count
if __name__ == '__main__':
try:
saved = main()
if saved > 0:
print("\n🎉 网页抓取测试成功!")
sys.exit(0)
else:
print("\n⚠️ 网页抓取测试完成,但未保存文章")
sys.exit(1)
except Exception as e:
print(f"\n❌ 测试过程中出现错误: {e}")
import traceback
traceback.print_exc()
sys.exit(1)