#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
爬虫：枞阳县人民政府 - 生态环境分局 - 建设项目环评文件审批
站点：www.zongyang.gov.cn
CMS：枞阳自定义政府信息公开平台
"""

import sys, os, re, requests, time
from bs4 import BeautifulSoup

_HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, _HERE)
from crawler_lib import push_to_searchdb
import urllib.parse

SITE_NAME = "枞阳县-环评审批"

HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'
}

BASE_URL = 'https://www.zongyang.gov.cn'
LIST_TPL = 'https://www.zongyang.gov.cn/openness/OpennessContent/showList/1442/47179/page_{page}.html'

session = requests.Session()
session.headers.update(HEADERS)


# ─── 正文取文本（2026-09-11）：行内节点直接拼接，只在块级边界 / <br> 处换行 ───
# ⚠️ 不要用 el.get_text("\n") 取正文 —— 它是「每个**文本节点**之间插 \n」，Word 粘贴的
#    公文把一行拆成 <span>提取码：</span>pwaj<span>。查阅…</span>，这些行内节点于是各自
#    成行（福泉 id=2095080103703914437 实例：`提取码：`/`pwaj`/`。查阅…` 各占一行）。
_BLOCK_TAGS = {'address', 'article', 'aside', 'blockquote', 'details', 'dialog', 'dd', 'div',
               'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2',
               'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'li', 'main', 'nav', 'ol',
               'p', 'pre', 'section', 'table', 'tbody', 'thead', 'tfoot', 'tr', 'td', 'th',
               'ul', 'center', 'caption'}


def body_text(el):
    """块级边界出换行、行内节点直接拼接、<br> 出换行（≈ 浏览器看到的换行结构）。"""
    if el is None:
        return ''
    import re as _re
    from bs4 import NavigableString
    out = []

    def walk(node):
        for ch in node.children:
            if isinstance(ch, NavigableString):
                out.append(str(ch))
            elif getattr(ch, 'name', None) == 'br':
                out.append('\n')
            elif getattr(ch, 'name', None) in _BLOCK_TAGS:
                out.append('\n')
                walk(ch)
                out.append('\n')
            else:
                walk(ch)
    walk(el)
    t = ''.join(out)
    t = _re.sub(r'[ \t\r\f\v]*\n[ \t\r\f\v]*', '\n', t)
    t = _re.sub(r'\n{3,}', '\n\n', t)
    return t.strip()


def safe_get(url, max_retries=3):
    """带重试的请求"""
    for attempt in range(max_retries):
        try:
            r = session.get(url, timeout=30)
            r.encoding = 'utf-8'
            if '禁止访问' in r.text:
                session.cookies.set('token_verified', 'true', domain='www.zongyang.gov.cn', path='/')
                continue
            return r
        except (requests.ConnectionError, requests.Timeout) as e:
            if attempt < max_retries - 1:
                time.sleep(2)
                continue
            print(f"    ⚠️ 请求失败({url}): {e}")
            return None
    return None


def fetch_list_page(page):
    """获取列表页"""
    url = LIST_TPL.format(page=page)
    r = safe_get(url)
    if r is None:
        return []
    
    soup = BeautifulSoup(r.text, 'html.parser')
    items = []
    
    for a in soup.find_all('a', href=re.compile(r'OpennessContent/show/\d+')):
        href = a.get('href', '')
        title = a.get('title', '') or a.get_text(strip=True)
        if not title:
            continue
        if href and not href.startswith('http'):
            href = BASE_URL + href
        
        li = a.find_parent('li')
        date_str = ''
        if li:
            date_span = li.find('span')
            if date_span:
                date_str = date_span.get_text(strip=True)
        
        items.append({'title': title, 'url': href, 'date': date_str})
    
    return items


def fetch_detail(url):
    """获取详情页正文"""
    r = safe_get(url)
    if r is None:
        return ''
    
    soup = BeautifulSoup(r.text, 'html.parser')
    
    content_div = soup.find(id=re.compile(r'Zoom', re.I))
    if not content_div:
        content_div = soup.find('div', class_=re.compile(r'detail', re.I))
    if not content_div:
        return ''
    
    parts = []
    def extract_nodes(node):
        for child in node.children:
            if child.name == 'p':
                text = child.get_text(' ', strip=True)
                if text:
                    parts.append(text)
            elif child.name == 'table':
                md = html_table_to_html(str(child))
                if md:
                    parts.append(md)
            elif child.name in ('div', 'section', 'article'):
                extract_nodes(child)
    extract_nodes(content_div)
    
    if not parts:
        text = body_text(content_div)
        if text:
            parts = [text]
    
    body = '\n\n'.join(parts)
    body = re.sub(r'(?<=[\u4e00-\u9fff])[ \t\u3000]+(?=[\u4e00-\u9fff])', '', body)
    return body

def html_table_to_html(table, base_url=""):
    """保留 HTML 表格结构，仅将相对链接/图片转绝对 URL"""
    from bs4 import BeautifulSoup
    tbl = BeautifulSoup(str(table), 'html.parser')
    for a in tbl.find_all('a'):
        href = a.get('href', '')
        if href and not href.startswith(('http', 'javascript', '#')):
            a['href'] = urllib.parse.urljoin(base_url, href) if base_url else href
    for img in tbl.find_all('img'):
        src = img.get('src', '')
        if src and not src.startswith(('http', '//', 'data:')):
            img['src'] = urllib.parse.urljoin(base_url, src) if base_url else src
    return str(tbl)


def main():
    print(f"[{SITE_NAME}] 开始")
    
    # 初始化 token
    r = safe_get(BASE_URL + '/')
    session.cookies.set('token_verified', 'true', domain='www.zongyang.gov.cn', path='/')
    
    all_items = []
    max_pages = 17
    
    for page in range(1, max_pages + 1):
        items = fetch_list_page(page)
        if not items:
            print(f"  第{page}页: 空，结束")
            break
        print(f"  第{page}页: {len(items)} 条")
        all_items.extend(items)
    
    print(f"\n列表合计: {len(all_items)} 条")
    
    if not all_items:
        print("  列表为空，退出")
        return
    
    db_items = []
    success = 0
    failed = 0
    for i, item in enumerate(all_items):
        url = item['url']
        title = item['title']
        date_str = item['date']
        print(f"  [{i+1}/{len(all_items)}] {title[:40]}...", end=' ')
        body = fetch_detail(url)
        if not body:
            print("⚠️ 空正文")
            failed += 1
        else:
            print(f"✅ {len(body)}字")
            success += 1
        
        db_items.append({
            'site_name': SITE_NAME,
            'source_url': url,
            'url': url,
            'title': title,
            'pub_date': date_str,
            'summary': body[:500] if body else '',
            'content': body,
        })
    
    push_to_searchdb(db_items, batch_label=SITE_NAME)
    print(f"\n[{SITE_NAME}] 完成: 共{len(all_items)}条, 正文成功{success}, 空{failed}")


if __name__ == '__main__':
    main()
