2025, Oct 19 21:33
1969 की Gazzetta Ufficiale Serie Generale के PDF को Selenium से भरोसेमंद तरीके से डाउनलोड करें
जानें क्यों requests/BeautifulSoup से 1969 Gazzetta Ufficiale Serie Generale के PDF लिंक नहीं मिलते, और Selenium से उन्हें भरोसेमंद तरीके से डाउनलोड करें.
1969 के Italian Gazzetta Ufficiale – Serie Generale से ऐतिहासिक PDF निकालना देखने में आसान लगता है: एक सार्वजनिक आर्काइव है, हर अंक के लिए डिटेल पेज हैं, और एक परिचित दिखने वाला डाउनलोड एंडपॉइंट भी है। व्यवहार में, स्थिर तरीकों से अक्सर कोई लिंक नहीं मिलता, और हाथ से बनाए गए डाउनलोड URL बाइनरी PDF के बजाय HTML त्रुटि पेज लौटा देते हैं। नीचे संक्षेप में बताया गया है कि ऐसा क्यों होता है और Selenium के साथ डाउनलोड को भरोसेमंद तरीके से कैसे स्वचालित करें।
समस्या का सारांश
1969 के आर्काइव इंडेक्स पर सीधी HTTP रिक्वेस्ट ठीक से काम करती हैं और डिटेल पेजों को सूचीबद्ध करना आसान है। मुश्किल तब शुरू होती है जब वास्तविक “pubblicazione completa non certificata” लिंक निकालने की कोशिश करते हैं। कई लाइव सत्रों में a.download_pdf जैसे अपेक्षित एंकर सर्वर-रेंडर किए गए HTML में मिलते ही नहीं, भले ही वे अन्य सहेजी गई प्रतियों में दिखाई दें। तिथि और अंक संख्या से /do/gazzetta/downloadPdf URL गढ़ने पर “Il pdf selezionato non è stato trovato” संदेश वाला HTML मिलता है। साल चुनने वाले कंट्रोल तक Selenium नेविगेशन भी साधारण सेलेक्टर के साथ नाजुक साबित होता है, क्योंकि वर्ष विकल्प छिपा हो सकता है, फ्रेम में हो सकता है या ओवरले से ढका हो सकता है; हालांकि, कीबोर्ड नेविगेशन से UI को चलाकर और फिर प्राप्त पेज सोर्स को पार्स करने पर असली डाउनलोड लिंक भरोसेमंद तरीके से दिखाई देते हैं।
न्यूनतम विफल तरीका (requests + BeautifulSoup)
नीचे दिया गया उदाहरण 1969 के सभी डिटेल पेज इकट्ठा करता है और फिर उनमें से किसी एक पर काम करने वाला PDF डाउनलोड लिंक खोजने की कोशिश करता है। नतीजा वही होता है जैसा ऊपर बताया गया: डिटेल पेज मिल जाते हैं, लेकिन लाइव DOM में डाउनलोड लिंक मौजूद नहीं होता।
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse, parse_qs
ORIGIN = "https://www.gazzettaufficiale.it"
TARGET_YEAR = 1969
YEAR_INDEX = f"{ORIGIN}/ricercaArchivioCompleto/serie_generale/{TARGET_YEAR}"
http = requests.Session()
http.headers.update({
    "User-Agent": "Mozilla/5.0",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Referer": ORIGIN,
})
# 1) डिटेल पेज एकत्र करें (तिथि + अंक संख्या)
resp = http.get(YEAR_INDEX, timeout=60)
resp.raise_for_status()
dom = BeautifulSoup(resp.text, "html.parser")
detail_pages = []
for node in dom.find_all("a", href=True):
    link = node["href"]
    if ("/gazzetta/serie_generale/caricaDettaglio" in link
        and "dataPubblicazioneGazzetta=" in link
        and "numeroGazzetta=" in link):
        detail_pages.append(urljoin(ORIGIN, link))
print("Detail pages found:", len(detail_pages))
print("Sample:", detail_pages[:3])
# 2) किसी एक डिटेल पेज के लिए, वास्तविक "download PDF" लिंक खोजने का प्रयास करें
detail_url = detail_pages[0]
resp = http.get(detail_url, timeout=60, headers={"Referer": YEAR_INDEX})
resp.raise_for_status()
dom = BeautifulSoup(resp.text, "html.parser")
# आम चयनकर्ताओं / टेक्स्ट को आजमाएं
download_anchor = (dom.select_one('a.download_pdf[href]')
                   or dom.select_one('a[href*="/do/gazzetta/downloadPdf"]'))
if not download_anchor:
    for node in dom.find_all("a", href=True):
        if "scarica il pdf" in (node.get_text() or "").lower():
            download_anchor = node
            break
print("Download link found on detail page?", bool(download_anchor))
if download_anchor:
    print("Download href:", urljoin(ORIGIN, download_anchor["href"]))
यह 1969 के लिए डिटेल पेजों की पूरी सूची निकाल देता है, पर उन पेजों पर डाउनलोड लिंक लगातार नहीं मिलता। उन अंकों के लिए डाउनलोड URL हाथ से बनाने पर बाइनरी PDF के बजाय “not found” संदेश वाला HTML लौटता है।
ऐसा क्यों होता है
इन ऐतिहासिक पेजों पर असरदार डाउनलोड एंकर server-rendered HTML में भरोसे से मौजूद नहीं होते, जो requests-आधारित स्क्रैपिंग को दिखता है। वर्ष चयनकर्ता जैसे UI तत्व छिपे, एम्बेडेड या ओवरले से ढके हो सकते हैं, और कुछ सत्रों में अपेक्षित download_pdf लिंक कभी बनते ही नहीं। downloadPdf URL हाथ से बनाने पर “Il pdf selezionato non è stato trovato” जैसे HTML उत्तर मिलते हैं, यानी एंडपॉइंट उस अनुरोध को स्वीकार नहीं करता। ऐसी स्थिति में ब्राउज़र-चालित तरीका उचित है। यह साइट को जरूरी client-side लॉजिक चलाने देता है और वही सत्र संदर्भ स्थापित करता है जिसकी सर्वर को अपेक्षा होती है। अनुभवजन्य तौर पर, यह तब जरूरी पड़ता है जब सर्वर कुकीज़, हेडरों पर निर्भर करता है या आर्काइव में पृष्ठ संरचना बदलती रहती है।
Selenium के साथ कारगर तरीका
नीचे दिया गया स्क्रिप्ट आधिकारिक “Formato grafico PDF” खोज खोलता है, कीबोर्ड नेविगेशन से वर्ष चुनता है, फॉर्म सबमिट करता है, परिणामस्वरूप पेज को पार्स करके वास्तविक a.download_pdf एंकर निकालता है, और फिर उसी ब्राउज़र सत्र में हर डाउनलोड URL पर रिक्वेस्ट करता है। save_dir को उस डायरेक्टरी पर सेट करें जहां आप PDF सहेजना चाहते हैं। हेडलेस मोड सक्षम है, और हर डाउनलोड का इंतजार करने के लिए एक सरल निश्चित sleep उपयोग किया गया है; चाहें तो .crdownload फाइलों के जरिए पूरा होने का पता लगाने के लिए हेल्पर भी इस्तेमाल कर सकते हैं।
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
import time
from lxml import html
SEARCH_URL = "https://www.gazzettaufficiale.it/ricerca/pdf/foglio_ordinario2/2/0/0?reset=true"
save_dir = "/home/lmc/tmp/test-ws/gaz"
chrome_cfg = webdriver.ChromeOptions()
chrome_cfg.add_argument("start-maximized")
chrome_cfg.add_argument("window-size=2880x1620")
chrome_cfg.add_argument("--headless")
chrome_cfg.set_capability("pageLoadStrategy", "normal")
chrome_cfg.add_argument("--enable-javascript")
cfg_prefs = {
    "profile.managed_default_content_settings.images": 2,
    "permissions.default.stylesheet": 2,
    "download.default_directory": save_dir,
    "download.prompt_for_download": False,
    "download.directory_upgrade": True,
}
chrome_cfg.add_experimental_option("prefs", cfg_prefs)
browser = webdriver.Chrome(options=chrome_cfg)
browser.implicitly_wait(30)
browser.get(SEARCH_URL)
try:
    year_select = browser.find_element(By.ID, 'annoPubblicazione')
    year_select.click()
    time.sleep(2)
    chain = ActionChains(browser)
    for _ in range(17):
        chain.send_keys(Keys.ARROW_DOWN)
    chain.send_keys(Keys.ENTER)
    chain.perform()
    search_btn = browser.find_element(By.XPATH, '//input[@name="cerca"]')
    search_btn.click()
    time.sleep(2)
    markup = browser.page_source
    tree = html.fromstring(markup)
    links = tree.xpath('//a[@class="download_pdf"]/@href')
    print(f"first link: {links[0] if links else 'none'}")
    print(f"total links: {len(links)}")
    for path in links:
        pdf_url = f"https://www.gazzettaufficiale.it{str(path)}"
        print(f"Downloading: {pdf_url}")
        browser.get(pdf_url)
        time.sleep(8)
except Exception as exc:
    print("Unexpected error during processing")
    raise exc
finally:
    browser.quit()
यदि आपके सिस्टम पर डाउनलोड अधूरा दिखाई दे, तो अस्थायी एक्सटेंशन देखकर यह सुनिश्चित करने के लिए कि Chrome फाइलें लिखना पूरा कर चुका है, एक सरल पोलिंग हेल्पर का उपयोग करें। नीचे दिया गया स्निपेट टाइमआउट और कॉन्फिगरेबल पोलिंग अंतराल का उपयोग करता है।
def monitor_downloads(dir_path, timeout=60, poll_each=1):
    import glob
    start = time.time()
    while glob.glob(f"{dir_path}/*.crdownload") and time.time() - start < timeout:
        time.sleep(poll_each)
    print(f"Download complete in {time.time() - start:.2f} seconds.")
यह क्यों महत्वपूर्ण है
सही सत्र संदर्भ के बिना सीधे डाउनलोड एंडपॉइंट पर जाना चुपचाप HTML त्रुटि पृष्ठ लौटा सकता है, जो .pdf एक्सटेंशन के साथ सहेज दिए जाएं तो सैकड़ों भ्रष्ट फाइलों में बदल जाते हैं। ब्राउज़र-नियंत्रित प्रवाह इस खतरे से बचाता है—ठीक वही कदम दोहराकर जो वास्तविक उपयोगकर्ता करता है: आधिकारिक UI में वर्ष चुनना, साइट को परिणाम भरने देना, और उसी सत्र के लिए बने एंकर लिंक का अनुसरण करना।
व्यावहारिक निष्कर्ष
जब आर्काइव दृश्य में साधारण HTTP क्लाइंट को download_pdf एंकर दिखाई न दें, तो “Il pdf selezionato non è stato trovato” लौटाने वाले तदर्थ URL को रिवर्स-इंजीनियर करने में वक्त न गंवाएं। साइट की अपनी UI पर निर्भर Selenium-चालित वर्कफ़्लो अपनाएं, जो वैध लिंक उजागर करे और सर्वर को अपेक्षित कुकीज़ व हेडर बनाए रखे। यदि ड्रॉपडाउन विकल्पों का सीधा चयन अस्थिर हो, तो कीबोर्ड नेविगेशन और Enter से चयन पक्का करें। डाउनलोड इंतजार रणनीति को अपने वातावरण के अनुसार समायोजित करें—या तो sleep बढ़ाएं, या अस्थायी फाइलें खत्म होने तक पोलिंग करें।
इस तरीके से आप 1969 की Serie Generale के लिए “pubblicazione completa non certificata” PDF भरोसे से, हेडलेस मोड में और बिना किसी मैन्युअल हस्तक्षेप के प्राप्त कर सकते हैं।