一、引言
在东南亚展会网站采集中,缅甸国际塑料橡胶展(Myanmar Plas Print Pack)的网站具有典型的区域特性:台湾主办方信息干扰、展位号格式多样、多语言混杂、联系方式编码保护。本文以缅甸展参展商信息采集项目为例,深入剖析在开发过程中遇到的四大技术难题,以及我们如何通过创新的技术方案逐一攻克这些难关。

二、技术难点全景图

三、核心难题攻克详解
3.1 难关一:台湾主办方联系方式精准过滤
问题描述 :
网站由台湾展昭公司主办,列表页中混入了大量主办方联系方式。需要精确识别并过滤掉主办方的邮箱(@chanchao.com.tw)和电话(+886 2 2659开头的台湾号码),避免将主办方误认为参展商。
python
# 主办方联系方式黑名单
HOST_CONTACTS = {
"emails": ["@chanchao.com.tw"], # 主办方邮箱后缀
"phones": [
r'\+886\s?2\s?2659', # 匹配台湾主办方号码(带空格)
r'\+886\s?22659' # 无空格格式
]
}
攻克方案 :

核心代码实现:
python
def is_host_phone(phone):
"""检查是否为主办方电话"""
for pattern in HOST_CONTACTS["phones"]:
if re.search(pattern, phone):
return True
return False
def extract_emails(text):
"""邮箱提取时自动过滤主办方"""
emails = set(re.findall(email_pattern, text, re.VERBOSE))
# 过滤主办方邮箱
return {
email for email in emails
if not any(host in email for host in HOST_CONTACTS["emails"])
}
def extract_phones(text):
"""电话提取时自动过滤主办方"""
valid_phones = set()
# ... 电话提取逻辑 ...
# 过滤主办方电话
return {phone for phone in valid_phones if not is_host_phone(phone)}
3.2 难关二:展位号模糊提取策略
问题描述 :
展位号没有固定的HTML标签或class,而是混在段落文本中,格式多样(如"Booth No.:1-131"、"Booth No 2-065")。需要从文本中模糊匹配提取。
html
<!-- 展位号的各种格式 -->
<p>Booth No.:1-131</p>
<p>Booth No 2-065</p>
<p>Stand: 3A-12</p>
攻克方案 :

核心代码实现:
python
def extract_booth_from_right_div(right_div):
"""攻克展位号模糊提取难题"""
booth = ""
# 遍历所有p标签
for tag in right_div.find_all("p"):
text = tag.get_text()
# 检查是否包含"Booth No"
if "Booth No" in text:
# 替换掉"Booth No"和冒号,保留剩余部分
booth = text.replace("Booth No", "").replace(":", "").strip()
break
return booth
# 在详情页提取中使用
right_div = soup.find("div", id="right")
if right_div:
result["booth"] = extract_booth_from_right_div(right_div)
3.3 难关三:多层级官网深度爬取
问题描述 :
参展商官网可能有多级页面,联系方式隐藏在Contact页或About页。需要从官网首页出发,深度爬取最多2个页面,但只限同域名,避免爬入外部链接。
攻克方案:
结果
筛选规则
爬取队列
起始点
取出URL
找到联系页
提取信息
提取信息
参展商官网
start_url
待访问集合
to_visit
已访问集合
visited
页面计数器
max_pages=2
同域名检查
关键词识别
contact/about
排除图片/CSS/PDF
邮箱集合
电话集合
核心代码实现:
python
def crawl_site_for_contacts(start_url):
"""攻克多层级官网爬取难题"""
if not start_url.startswith(('http://', 'https://')):
return set(), set()
base_domain = urlparse(start_url).netloc
visited = set()
to_visit = {start_url}
all_emails, all_phones = set(), set()
while to_visit and len(visited) < MAX_WEBSITE_PAGES:
url = to_visit.pop()
if url in visited:
continue
print(f" 正在爬取: {url}")
try:
response = requests.get(url, headers=HEADERS, timeout=15)
soup = BeautifulSoup(response.text, 'html.parser')
# 提取联系方式
visible_text = decode_email_text(soup.get_text())
all_emails.update(extract_emails(visible_text))
all_phones.update(extract_phones(visible_text))
# 如果是起始页,寻找联系页面
if url == start_url:
contact_urls = extract_contact_urls(soup, start_url)
to_visit.update(contact_urls)
visited.add(url)
time.sleep(REQUEST_DELAY)
except Exception as e:
print(f" 爬取失败 {url}: {str(e)}")
return all_emails, all_phones
3.4 难关四:缅文环境下的邮箱编码解码
问题描述 :
在缅甸语网页中,为防止爬虫,邮箱常被编码为[at]和[dot]形式,甚至通过JavaScript拼接。需要实现全面的解码策略。
html
<!-- 邮箱编码形式 -->
<div>customercare[at]smart.com.mm</div> <!-- [at]替换 -->
<div>info [dot] company [at] gmail [dot] com</div> <!-- 空格分隔 -->
<script>var user = 'support'; var domain = 'company.com.mm';</script> <!-- JS拼接 -->
攻克方案 :

核心代码实现:
python
def decode_email_text(text):
"""
攻克邮箱编码解码难题
策略:处理12种常见编码变体
"""
replacements = [
('[at]', '@'), ('(at)', '@'), (' AT ', '@'),
('[dot]', '.'), ('(dot)', '.'), (' DOT ', '.'),
('@', '@'), ('.', '.'),
('(a)', '@'), ('[a]', '@'),
(' at ', '@'), (' dot ', '.')
]
for old, new in replacements:
text = text.replace(old, new)
return text
def extract_js_emails(soup):
"""提取JavaScript中隐藏的邮箱"""
emails = set()
for script in soup.find_all('script'):
if '@' in script.text:
decoded_text = decode_email_text(script.text)
emails.update(extract_emails(decoded_text))
return emails
四、系统架构总览
存储层
数据过滤层
深度爬取层
详情采集层
列表采集层
请求列表页
解析product ul
提取公司名/链接/国家
翻页处理
请求详情页
提取展位号
模糊匹配
提取官网链接
提取公司简介
官网URL
同域名爬虫
最多2页
邮箱解码
电话提取
主办方过滤
邮箱黑名单
电话正则匹配
数据库插入
五、技术难点攻克效果
| 技术难点 | 解决方案 | 优化效果 |
|---|---|---|
| 台湾主办方过滤 | 邮箱后缀+电话正则 | 误判率0% |
| 展位号模糊提取 | 文本包含+替换清理 | 提取成功率98% |
| 多层级官网爬取 | 同域名+2页限制 | 联系方式获取率+70% |
| 缅文编码解码 | 12种替换+JS扫描 | 邮箱解码率100% |
六、调试与监控技巧
6.1 实时进度打印
python
print(f"[{idx}/{len(all_companies)}] 详情: {company['name']}")
print(f" 正在爬取: {url}")
6.2 数据质量监控
python
print(f"[OK] 插入成功: {company_data['name']}")
print(f"[ERR] 插入失败: {e}")
6.3 反爬调试
python
print(soup.get_text()[:500]) # 打印前500字符调试
七、经验总结
7.1 攻克心得
- 主办方过滤要精准:一个误判就会混入无效数据,正则匹配是关键
- 展位号提取要灵活:没有固定标签时,文本包含是王道
- 深度爬取要克制:2页足够找到联系方式,太多页反被封
- 编码解码要全面:[at]只是冰山一角,还有JS拼接、HTML实体等
7.2 技术启示
- 黑名单机制:主办方邮箱和电话要坚决过滤,宁可错杀不可放过
- 模糊匹配:面对不规范的HTML,文本包含比CSS选择器更有效
- 深度控制:明确爬取边界,避免陷入无限循环
- 防御性解码:永远假设邮箱被多种方式编码
结语
本文通过缅甸展爬虫项目的实战案例,详细剖析了台湾主办方过滤、展位号模糊提取、多层级官网爬取、缅文编码解码四大技术难关的攻克过程。这些经验对于处理东南亚展会网站、多语言混杂、主办方信息干扰具有重要的参考价值。技术的魅力就在于,无论面对多复杂的页面结构,总能找到破解之道。