paste_zayo

Untitled

Aug 21st, 2025
10
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.04 KB | None | 0 0
  1. import os, re, time, random
  2. import pandas as pd
  3. import requests
  4. from bs4 import BeautifulSoup
  5.  
  6. BASE = "http://www.isofmap.bg"
  7. SEARCH_URL = f"{BASE}/search"
  8.  
  9. BASE_DIR = r"C:\Working_desktop\GATE_stuff\tst_isofmap"
  10. INPUT_XLSX = os.path.join(BASE_DIR, "isofmap.xlsx") # колони: kv, upi
  11. OUTPUT_CSV = os.path.join(BASE_DIR, "isofmap_results.csv")
  12. DEBUG_HTML = os.path.join(BASE_DIR, "last_response.html")
  13.  
  14. HEADERS = {
  15. "User-Agent": "Mozilla/5.0",
  16. "Referer": f"{BASE}/",
  17. "Origin": BASE,
  18. "X-Requested-With": "XMLHttpRequest",
  19. }
  20.  
  21. TOKEN_PATTERNS = [
  22. re.compile(r'name=["\']token["\']\s+value=["\']([^"\']+)["\']', re.I),
  23. re.compile(r'\btoken["\']?\s*[:=]\s*["\']([^"\']+)["\']'),
  24. ]
  25.  
  26. def fetch_token(session: requests.Session) -> str:
  27. r = session.get(BASE, headers=HEADERS, timeout=30)
  28. r.raise_for_status()
  29. html = r.text
  30. for pat in TOKEN_PATTERNS:
  31. m = pat.search(html)
  32. if m:
  33. return m.group(1)
  34. soup = BeautifulSoup(html, "html.parser")
  35. token_input = soup.find("input", {"name": "token"})
  36. if token_input and token_input.get("value"):
  37. return token_input["value"]
  38. raise RuntimeError("Не намерих token в началната страница.")
  39.  
  40. def query(session: requests.Session, token: str, kv: str, upi: str) -> dict:
  41. data = {
  42. "token": token,
  43. "searchType": "searchByRegulation",
  44. "admRegion": "",
  45. "place": "",
  46. "quarter": kv,
  47. "parcel": upi,
  48. "regDestine": "",
  49. "regPurpose": "",
  50. }
  51. r = session.post(SEARCH_URL, data=data, headers=HEADERS, timeout=30)
  52. r.raise_for_status()
  53.  
  54. # запази HTML за дебъг
  55. with open(DEBUG_HTML, "w", encoding="utf-8") as f:
  56. f.write(r.text)
  57.  
  58. soup = BeautifulSoup(r.text, "lxml")
  59.  
  60. # ---------- Стратегия 1: data-title колони ----------
  61. td_main = soup.find("td", attrs={"data-title": "Основна информация"})
  62. td_extra = soup.find("td", attrs={"data-title": "Допълнителна информация"})
  63. if td_main and td_extra:
  64. # опитай да вземеш и първата клетка от същия ред (ID/етикет)
  65. upi_cell = ""
  66. tr = td_main.find_parent("tr")
  67. if tr:
  68. tds = tr.find_all("td")
  69. if tds:
  70. upi_cell = tds[0].get_text(strip=True)
  71. return {
  72. "found": 1,
  73. "upi_id_or_label": upi_cell,
  74. "main_info": td_main.get_text(strip=True),
  75. "extra_info": td_extra.get_text(strip=True),
  76. }
  77.  
  78. # ---------- Стратегия 2: таблица след секцията „УПИ“ ----------
  79. upi_anchor = soup.find(lambda t: t.get_text(strip=True) == "УПИ")
  80. if not upi_anchor:
  81. # понякога е текстов възел
  82. upi_txt = soup.find(string=lambda s: isinstance(s, str) and s.strip() == "УПИ")
  83. if upi_txt:
  84. upi_anchor = upi_txt.parent
  85.  
  86. if upi_anchor:
  87. table = upi_anchor.find_next("table")
  88. if table:
  89. data_tr = None
  90. for tr in table.find_all("tr"):
  91. tds = tr.find_all("td")
  92. if len(tds) >= 3:
  93. data_tr = tr
  94. break
  95. if data_tr:
  96. tds = data_tr.find_all("td")
  97. return {
  98. "found": 1,
  99. "upi_id_or_label": tds[0].get_text(strip=True),
  100. "main_info": tds[1].get_text(strip=True),
  101. "extra_info": tds[2].get_text(strip=True),
  102. }
  103.  
  104. # ---------- Стратегия 3: regex върху текст след „УПИ“ ----------
  105. # вземи текста след котвата „УПИ“
  106. full_text = " ".join(soup.stripped_strings)
  107. # опитай да изрежеш всичко след „УПИ“
  108. part = full_text
  109. if "УПИ" in full_text:
  110. part = full_text.split("УПИ", 1)[1]
  111.  
  112. # шаблон: ... Намерени резултати: 1 Основна информация Допълнителна информация <ID> <MAIN> <EXTRA>
  113. m = re.search(
  114. r"Намерени\s+резултати:\s*1\s*Основна\s+информация\s*Допълнителна\s+информация\s*(\d+)\s*(.+?)\s{2,}(.+?)\s*(?:Намерени\s+резултати:|$)",
  115. part,
  116. flags=re.S
  117. )
  118. if m:
  119. upi_id = m.group(1).strip()
  120. main_info = re.sub(r"\s+", " ", m.group(2)).strip()
  121. extra_info = re.sub(r"\s+", " ", m.group(3)).strip()
  122. return {
  123. "found": 1,
  124. "upi_id_or_label": upi_id,
  125. "main_info": main_info,
  126. "extra_info": extra_info,
  127. }
  128.  
  129. return {"found": 0, "reason": "no_row", "html_len": len(r.text)}
  130.  
  131. def main():
  132. if not os.path.exists(INPUT_XLSX):
  133. raise FileNotFoundError(f"Липсва входният Excel: {INPUT_XLSX}")
  134.  
  135. df = pd.read_excel(INPUT_XLSX)
  136. if not {"kv", "upi"}.issubset(df.columns):
  137. raise ValueError("Excel-ът трябва да има колони 'kv' и 'upi'.")
  138.  
  139. out = []
  140. with requests.Session() as s:
  141. token = fetch_token(s)
  142. for _, rec in df.iterrows():
  143. kv = str(rec["kv"]).strip()
  144. upi = str(rec["upi"]).strip()
  145. res = query(s, token, kv, upi)
  146. # ако token се окаже проблем – опитай един refresh
  147. if res.get("found") == 0 and res.get("html_len", 0) < 100:
  148. token = fetch_token(s)
  149. res = query(s, token, kv, upi)
  150. res.update({"kv": kv, "upi": upi})
  151. out.append(res)
  152. time.sleep(0.5 + random.random()*0.6)
  153.  
  154. pd.DataFrame(out).to_csv(OUTPUT_CSV, index=False, encoding="utf-8-sig")
  155. print("Готово ->", OUTPUT_CSV, "\n(ако има проблем, виж HTML в)", DEBUG_HTML)
  156.  
  157. if __name__ == "__main__":
  158. main()
  159.  
Advertisement
Add Comment
Please, Sign In to add comment