日期: 2024-12-29 主题: 地址信息提取、网络爬虫与数据分析
继续完善小区分析工具。这次的需求是从原始地址中提取小区名称,然后从网上获取建成年份信息。
地址格式五花八门,需要智能提取:
def extract_community_name(self, address: str) -> str:
"""优化后的小区名称提取"""
# 定义小区关键词
community_keywords = ['花园', '小区', '广场', '家园', '苑', '新村', '公寓', '别墅', '城']
# 1. 首先尝试匹配完整的小区名称
for keyword in community_keywords:
pattern = f'([^号路街巷]{1,20}?{keyword})'
match = re.search(pattern, address)
if match:
community = match.group(1)
# 清理门牌号
community = re.sub(r'^\d+号', '', community)
return community.strip()
# 2. 检查是否有"村"结尾的地址
village_match = re.search(r'([^\d]+村)[^\d]*$', address)
if village_match:
return village_match.group(1)
# 3. 提取路名
road_match = re.search(r'([^省市区县镇村\d]+?[路街道])', address)
if road_match:
return road_match.group(1)
return address提取策略:
- 优先匹配带关键词的小区名(花园、小区等)
- 其次匹配村庄名称
- 最后提取路名
- 去除门牌号等干扰信息
从房产网站获取小区信息:
class LianjiaAnalyzer:
def __init__(self):
self.headers = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X)',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9'
}
self.old_community_year = 2010
def get_community_info(self, community_name: str) -> Dict:
try:
search_url = f"https://m.ke.com/changzhou/xiaoqu/rs{quote(community_name)}/"
response = requests.get(search_url, headers=self.headers, timeout=10)
# 匹配小区链接
detail_pattern = r'href="(/changzhou/xiaoqu/\d+/)"'
matches = re.findall(detail_pattern, response.text)
if matches:
detail_url = f"https://m.ke.com{matches[0]}"
detail_response = requests.get(detail_url, headers=self.headers)
# 提取建成年份
year_pattern = r'建成年代</div><div[^>]*>(\d{4})[年-](\d{4})?年?'
year_match = re.search(year_pattern, detail_response.text)
if year_match:
start_year = int(year_match.group(1))
end_year = int(year_match.group(2)) if year_match.group(2) else start_year
return {
"建成年份": f"{start_year}-{end_year}",
"最早建成": start_year
}
return {}
except Exception as e:
print(f"获取小区信息出错: {e}")
return {}技术要点:
- 模拟移动端请求,兼容性更好
- 用正则提取年份,处理年份范围(如 2000-2008 年)
- 完善的错误处理
def analyze_communities(filename: str, limit: int = 10) -> pd.DataFrame:
"""分析小区列表"""
analyzer = LianjiaAnalyzer()
results = []
with open(filename, 'r', encoding='utf-8') as f:
addresses = [line.strip() for line in f if line.strip()][:limit]
for idx, address in enumerate(addresses, 1):
result = analyzer.analyze_community(address)
results.append(result)
time.sleep(2) # 控制请求频率
return pd.DataFrame(results)| 原地址 | 提取结果 |
|---|---|
| 劳动西路99号新世界花园2-5号 | 新世界花园 |
| 延政西大道325号湖畔春秋花园22区202幢 | 湖畔春秋花园 |
| 南夏墅街道三河村委金家塘71号 | 金家塘村 |
数据获取:
- 控制请求频率,避免被封
- 使用合适的 User-Agent
- 实现错误重试
- 保存中间数据
数据处理:
- 规范化清洗流程
- 保存详细日志
- 定期验证准确性
今天主要在写正则表达式,提取地址中的小区名称。
地址数据比想象中混乱。有的写"xx路xx号xx小区",有的写"xx小区xx栋",有的直接写村名。没有通用的解析规则,只能用多个正则依次尝试。这让我理解了为什么 NLP 中的命名实体识别(NER)是个难题。
爬虫部分比较顺利,但要注意法律风险。爬取公开信息用于内部分析一般没问题,但不能用于商业用途或公开发布。另外要控制请求频率,不能给目标网站造成压力。
一个小技巧:用移动端 User-Agent 通常能获得更简洁的页面,更容易解析。
- 中文地址解析库(如 cpca)
- 命名实体识别(NER)
- 爬虫框架(Scrapy)
- 数据采集的合规性