Python के साथ Bing खोज परिणामों को कैसे स्क्रैप करें

टिप्पणियाँ: 0

वेब एनालिटिक्स केवल Google तक सीमित नहीं है। Bing SERP का एक वैकल्पिक दृष्टिकोण प्रदान करता है, जो SEO रिसर्च, लिंक प्रॉस्पेक्टिंग, ब्रांड मॉनिटरिंग, प्रतिस्पर्धी विश्लेषण और कंटेंट रिसर्च के लिए उपयोगी है। Python इस प्रकार के स्वचालन के लिए एक आदर्श उपकरण है: परिपक्व इकोसिस्टम, सरल सिंटैक्स और HTML पार्सिंग तथा JSON के साथ काम करने के लिए मजबूत लाइब्रेरीज़ Bing खोज परिणामों को तेज़ और अधिक सुविधाजनक तरीके से स्क्रैप करने की अनुमति देती हैं।

Google की बजाय Bing पर ध्यान क्यों दें?

Bing अपने स्वयं के रैंकिंग दिशानिर्देशों और गुणवत्ता संकेतों का उपयोग करता है, इसलिए इसके परिणाम अक्सर Google से भिन्न होते हैं। यह ऑर्गेनिक सर्च और लॉन्ग-टेल क्वेरीज़ में अतिरिक्त अवसर खोजने के लिए मूल्यवान है। अपने वेबमास्टर सुझावों में, Bing प्रासंगिकता, गुणवत्ता/विश्वास, उपयोगकर्ता सहभागिता, ताज़गी, भौगोलिक कारक और पेज स्पीड पर जोर देता है—Google की तुलना में संकेतों का एक अलग संतुलन। यही कारण है कि कुछ पेज विशेष रूप से Bing पर अधिक ऊँची रैंक करते हैं।

Bing खोज परिणामों को स्क्रैप करने के व्यावहारिक उपयोग:

  • अपनी लिंक-बिल्डिंग डोनर सूची का विस्तार करना—यह इंजन कभी-कभी उन साइटों को ऊपर लाता है जो Google के शीर्ष 10 में नहीं दिखतीं।
  • PAA (“People also ask”) और Bing के यूनिवर्सल SERP एलिमेंट्स (वीडियो, कैरोसेल) को ट्रैक करना, ताकि कंटेंट रणनीति को समायोजित किया जा सके।

Bing खोज से कौन-सा डेटा निकाला जा सकता है?

“क्लासिक” SERP से आप भरोसेमंद तरीके से निकाल सकते हैं:

  • Title;
  • URL (दस्तावेज़ लिंक);
  • Snippet (विवरण);
  • Position in the results (क्रमांक);
  • कुछ यूनिवर्सल परिणाम: “Related/People also ask”, एम्बेडेड इमेज/वीडियो परिणाम (जब मुख्य SERP में सीधे शामिल हों)।

महत्वपूर्ण: Bing की मार्कअप संरचना समय-समय पर बदलती रहती है, इसलिए नीचे दिए गए कोड में चयनकर्ताओं को समायोजन की आवश्यकता हो सकती है।

Bing खोज को स्क्रैप करते समय कानूनी और नैतिक विचार

  • Microsoft की Terms of Use का पालन करें: वेब डेटा के “आधिकारिक” एक्सेस के लिए Microsoft अब Azure AI Agents के हिस्से के रूप में Grounding with Bing Search प्रदान करता है। सार्वजनिक Bing Search APIs को 11 अगस्त 2025 को पूरी तरह बंद कर दिया गया था।
  • Grounding with Bing Search के अपने TOU और सीमाएँ हैं: इसका उपयोग Azure एजेंट्स के माध्यम से किया जाता है, और परिणाम “कच्चे” JSON SERP डेटा के बजाय एजेंट की प्रतिक्रियाओं में वापस आते हैं।
  • robots.txt का सम्मान करें और होस्ट पर अनावश्यक लोड से बचें—robots का पालन करना स्क्रैपिंग की मूल नैतिकता है।

Scraping के लिए अपना Python वातावरण सेट करना

मूलभूत पैकेज इंस्टॉल करें:

pip install requests beautifulsoup4 lxml fake-useragent selenium
  • requests — HTTP क्लाइंट (जो आपको User-Agent जैसे हेडर सेट करने की अनुमति देता है);
  • beautifulsoup4 + lxml — HTML पार्सिंग;
  • fake-useragent — रैंडम UA जनरेशन (या अपनी स्वयं की सूची तैयार करें);
  • selenium — आवश्यकता पड़ने पर डायनेमिक ब्लॉक्स रेंडर करता है।

मेथड 1 – Requests और BeautifulSoup के माध्यम से Bing स्क्रैप करना

हम इसे वर्कफ़्लो प्रदर्शित करने के आधार के रूप में उपयोग करेंगे: GET अनुरोध भेजना, User-Agent सेट करना, परिणाम कार्ड पार्स करना, और शीर्षक, URL, स्निपेट और स्थिति एकत्र करना।

import time
import random
from typing import List, Dict
import requests
from bs4 import BeautifulSoup

BING_URL = "https://www.bing.com/search"

HEADERS_POOL = [
    # You can add more — or use fake-useragent
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
    "(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_5) AppleWebKit/605.1.15 "
    "(KHTML, like Gecko) Version/17.0 Safari/605.1.15",
]

def fetch_serp(query: str, count: int = 10, first: int = 1,
               proxy: str | None = None) -> List[Dict]:
    """
Returns a list of results: title, url, snippet, position.
`first` — starting position (pagination), `count` — how many records to fetch.

    """
    params = {"q": query, "count": count, "first": first}
    headers = {"User-Agent": random.choice(HEADERS_POOL)}
    proxies = {"http": proxy, "https": proxy} if proxy else None

    resp = requests.get(BING_URL, params=params, headers=headers,
                        proxies=proxies, timeout=15)
    resp.raise_for_status()
    soup = BeautifulSoup(resp.text, "lxml")

   # Typical Bing markup: <li class="b_algo"> ... <h2><a href="">Title</a></h2>
    items = []
    for idx, li in enumerate(soup.select("li.b_algo"), start=first):
        a = li.select_one("h2 a")
        if not a:
            continue
        title = a.get_text(strip=True)
        url = a.get("href")
         # Snippet is often in .b_caption p or simply the first <p>
        sn_el = li.select_one(".b_caption p") or li.select_one("p")
        snippet = sn_el.get_text(" ", strip=True) if sn_el else ""
        items.append({
            "position": idx,
            "title": title,
            "url": url,
            "snippet": snippet
        })
    return items

if __name__ == "__main__":
    data = fetch_serp("python web scraping tutorial", count=10)
    for row in data:
        print(f"{row['position']:>2}. {row['title']} -- {row['url']}")
        print(f"   {row['snippet']}\n")

व्याख्या:

  • पृष्ठक्रम (pagination) के लिए count/first पैरामीटर का उपयोग करें।
  • सेलेक्टर्स li.b_algo h2 a और .b_caption p आधारभूत हैं; लेआउट बदल सकता है (DevTools में निरीक्षण करें)।
  • ज़रूरत पड़ने पर प्रॉक्सी जोड़ें और अनुरोधों के बीच विराम को नियंत्रित करें।
  • हम नीचे इस उदाहरण को थोड़ा और बेहतर करेंगे, क्योंकि मौजूदा परिस्थितियों में यह हमारे उद्देश्य के लिए सबसे प्रभावी तरीका है।

मेथड 2 — API के माध्यम से Bing Search परिणाम स्क्रैप करना (2025 की स्थिति)

Microsoft का सार्वजनिक Bing scraper API अगस्त 2025 में बंद कर दिया गया। Microsoft Azure AI Agents के भीतर Grounding with Bing Search पर माइग्रेट करने की सलाह देता है।

व्यावहारिक रूप से इसका मतलब:

  • “कच्चे” JSON SERP डेटा वाला क्लासिक REST endpoint अब अधिकांश डेवलपर्स के लिए उपलब्ध नहीं है।
  • Grounding with Bing Search एक Azure एजेंट के अंदर टूल के रूप में जुड़ा होता है; एजेंट वेब “खोज” सकता है और एक संश्लेषित उत्तर लौटाता है। इस सेवा के अपने TOU और सीमाएँ हैं: इसे कच्चे SERP डेटा के बड़े पैमाने पर निष्कर्षण (bulk extraction) के लिए डिज़ाइन नहीं किया गया।

JSON में raw SERP का विकल्प

तृतीय-पक्ष SERP APIs/प्लेटफ़ॉर्म (उदाहरण: Apify Bing Search Scraper) का उपयोग करें, जो संरचित परिणाम लौटाते हैं: शीर्षक, URL, स्निपेट, स्थिति आदि।

न्यूनतम Apify अनुरोध उदाहरण:

import requests

API_TOKEN = "apify_xxx"  # store in ENV
actor = "tri_angle/bing-search-scraper"
payload = {
    "queries": ["python web scraping tutorial"],
    "countryCode": "US",
    "includeUnfilteredResults": False
}

r = requests.post(
    f"https://api.apify.com/v2/acts/{actor}/runs?token={API_TOKEN}",
    json=payload, timeout=30
)
run = r.json()
# Retrieve dataset items using run['data']['defaultDatasetId']

Apify के दस्तावेज़ ऑर्गेनिक परिणाम, PAA, संबंधित क्वेरीज़ और अन्य तत्वों का समर्थन करते हैं। सुनिश्चित करें कि आपका उपयोग-मामला प्लेटफ़ॉर्म नियमों और आपके क्षेत्राधिकार के कानूनों के अनुरूप हो।

सुझाव: यदि आप Azure AI Agents स्टैक में काम करते हैं और आपको केवल LLM के लिए ग्राउंडेड रेफरेंसेज़ चाहिए (raw JSON नहीं), तो Grounding with Bing Search वाली गाइड पढ़ें।

मेथड 3 – Selenium के साथ डायनामिक कंटेंट पार्स करना

जब SERP में कैरोसेल, इंटरैक्टिव ब्लॉक्स, या JavaScript द्वारा रेंडर किया गया कंटेंट शामिल हो, तो Selenium (Headless Chrome/Firefox) का उपयोग करें।

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options

def selenium_bing(query: str, headless: bool = True):
    opts = Options()
    if headless:
        opts.add_argument("--headless=new")
    opts.add_argument("--disable-gpu")
    opts.add_argument("--no-sandbox")
    with webdriver.Chrome(options=opts) as driver:
        driver.get("https://www.bing.com/")
        box = driver.find_element(By.NAME, "q")
        box.send_keys(query)
        box.submit()

        # Consider adding explicit waits via WebDriverWait
        cards = driver.find_elements(By.CSS_SELECTOR, "li.b_algo h2 a")
        results = []
        for i, a in enumerate(cards, start=1):
            results.append({"position": i, "title": a.text, "url": a.get_attribute("href")})
        return results

if __name__ == "__main__":
    print(selenium_bing("site:docs.python.org requests headers"))

ड्राइवर इंस्टॉलेशन और WebDriverWait उदाहरणों के लिए आधिकारिक Selenium दस्तावेज़ देखें।

व्यावहारिक समाधान: पार्सिंग रणनीति और उदाहरण कोड

अंतिम इम्प्लीमेंटेशन के लिए, हम सीधे HTML से Bing स्क्रैपिंग करेंगे:

  1. https://www.bing.com/search पर HTTP अनुरोध भेजें।
  2. User-Agent सेट करें।
  3. शीर्षक, URLs और स्निपेट निकालने के लिए BeautifulSoup + lxml के माध्यम से HTML पार्स करें।

इस तरीके से आपको Microsoft अकाउंट की आवश्यकता नहीं होती और आप किसी तृतीय-पक्ष पेड API पर निर्भर नहीं रहते। परिणाम चयन के लिए हम li.b_algo रिज़ल्ट-कार्ड कंटेनर का उपयोग करते हैं, जो Bing के ऑर्गेनिक ब्लॉक्स में आम है।

कार्यशील उदाहरण (pagination, delays, वैकल्पिक proxy)

from __future__ import annotations

import argparse
import csv
import dataclasses
import pathlib
import random
import sys
import time
from typing import List, Optional, Tuple

import requests
from bs4 import BeautifulSoup, FeatureNotFound

BING_URL = "https://www.bing.com/search"

# Pool of user agents
UA_POOL = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
]

@dataclasses.dataclass
class SerpItem:
    position: int
    title: str
    url: str
    snippet: str


def build_session(proxy: Optional[str] = None) -> requests.Session:
    """Create a session with baseline headers and an optional proxy."""
    s = requests.Session()
    s.headers.update(
        {
            "User-Agent": random.choice(UA_POOL),
            "Accept-Language": "uk-UA,uk;q=0.9,en;q=0.8",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        }
    )
    if proxy:
        # Requests proxy dict format: {'http': 'http://host:port', 'https': 'http://host:port'}
        s.proxies.update({"http": proxy, "https": proxy})
    return s


def _soup_with_fallback(html: str) -> BeautifulSoup:
    """Parse HTML with a forgiving fallback chain: lxml -> html.parser -> html5lib (if available)."""
    for parser in ("lxml", "html.parser", "html5lib"):
        try:
            return BeautifulSoup(html, parser)
        except FeatureNotFound:
            continue
    # If none are installed, bs4 will raise; let it propagate
    return BeautifulSoup(html, "html.parser")


def parse_serp_html(html: str, start_pos: int) -> List[SerpItem]:
    """Extract organic results from Bing SERP HTML."""
    soup = _soup_with_fallback(html)
    items: List[SerpItem] = []

    # Organic blocks typically look like <li class="b_algo"> with h2>a and a snippet under .b_caption p or the first <p>.
    for i, li in enumerate(soup.select("li.b_algo"), start=start_pos):
        a = li.select_one("h2 > a")
        if not a:
            continue
        title = (a.get_text(strip=True) or "").strip()
        url = a.get("href") or ""
        p = li.select_one(".b_caption p") or li.select_one("p")
        snippet = (p.get_text(" ", strip=True) if p else "").strip()
        items.append(SerpItem(position=i, title=title, url=url, snippet=snippet))

    return items


def fetch_bing_page(
    session: requests.Session,
    query: str,
    first: int = 1,
    count: int = 10,
    cc: str = "UA",
    setlang: str = "uk",
    timeout: int = 20,
) -> List[SerpItem]:
    """Download one results page and return parsed items."""
    params = {
        "q": query,
        "count": count,   # 10, 15, 20...
        "first": first,   # 1, 11, 21...
        "cc": cc,         # country code for results
        "setlang": setlang,  # interface/snippet language
    }
    r = session.get(BING_URL, params=params, timeout=timeout)
    r.raise_for_status()
    return parse_serp_html(r.text, start_pos=first)


def search_bing(
    query: str,
    pages: int = 1,
    count: int = 10,
    pause_range: Tuple[float, float] = (1.2, 2.7),
    proxy: Optional[str] = None,
    cc: str = "UA",
    setlang: str = "uk",
    timeout: int = 20,
) -> List[SerpItem]:
    """Iterate over pages and return an aggregated list of results."""
    session = build_session(proxy=proxy)
    all_items: List[SerpItem] = []
    first = 1
    for _ in range(pages):
        items = fetch_bing_page(
            session, query, first=first, count=count, cc=cc, setlang=setlang, timeout=timeout
        )
        all_items.extend(items)
        time.sleep(random.uniform(*pause_range))  # polite delay
        first += count
    return all_items


def _normalize_cell(s: str) -> str:
    """Optional: collapse internal whitespace so simple viewers show one‑line cells."""
    # Convert tabs/newlines/multiple spaces to a single space
    return " ".join((s or "").split())


def save_csv(
    items: List[SerpItem],
    path: str,
    excel_friendly: bool = False,
    normalize: bool = False,
    delimiter: str = ",",
) -> int:
    """
Write results to CSV.
— excel_friendly=True -> write UTF‑8 with BOM (utf‑8‑sig) so Excel auto‑detects Unicode.
— normalize=True -> collapse whitespace inside string fields.
— delimiter -> change if your consumer expects ';', etc.
Returns the number of rows written (excluding header).

    """
    p = pathlib.Path(path)
    p.parent.mkdir(parents=True, exist_ok=True)

    encoding = "utf-8-sig" if excel_friendly else "utf-8"

    # newline='' is required so Python's csv handles line endings correctly on all platforms
    with p.open("w", newline="", encoding=encoding) as f:
        writer = csv.DictWriter(
            f,
            fieldnames=["position", "title", "url", "snippet"],
            delimiter=delimiter,
            quoting=csv.QUOTE_MINIMAL,
        )
        writer.writeheader()
        for it in items:
            row = dataclasses.asdict(it)
            if normalize:
                row = {k: _normalize_cell(v) if isinstance(v, str) else v for k, v in row.items()}
            writer.writerow(row)
    return len(items)


def main() -> int:
    ap = argparse.ArgumentParser(description="Bing SERP scraper (Requests + BS4)")
    ap.add_argument("-q", "--query", required=True, help="Search query")
    ap.add_argument("--pages", type=int, default=1, help="Number of pages (x count)")
    ap.add_argument("--count", type=int, default=10, help="Results per page")
    ap.add_argument("--cc", default="UA", help="Country code for results (cc)")
    ap.add_argument("--setlang", default="uk", help="Interface/snippet language (setlang)")
    ap.add_argument("--proxy", help="Proxy, e.g. http://user:pass@host:port")
    ap.add_argument("--csv", help="Path to CSV to save results")
    ap.add_argument(
        "--excel-friendly",
        action="store_true",
        help="Add BOM (UTF‑8‑SIG) so Excel opens the file correctly",
    )
    ap.add_argument(
        "--normalize-cells",
        action="store_true",
        help="Remove line breaks and extra spaces in cells",
    )
    ap.add_argument(
        "--delimiter",
        default=",",
        help="CSV delimiter (default ','); e.g.: ';'",
    )
    args = ap.parse_args()

    try:
        items = search_bing(
            args.query,
            pages=args.pages,
            count=args.count,
            proxy=args.proxy,
            cc=args.cc,
            setlang=args.setlang,
        )
    except requests.HTTPError as e:
        print(f"[ERROR] HTTP error: {e}", file=sys.stderr)
        return 2
    except requests.RequestException as e:
        print(f"[ERROR] Network error: {e}", file=sys.stderr)
        return 2

    if args.csv:
        try:
            n = save_csv(
                items,
                args.csv,
                excel_friendly=args.excel_friendly,
                normalize=args.normalize_cells,
                delimiter=args.delimiter,
            )
            print(f"Saved {n} rows to {args.csv}")
        except OSError as e:
            print(f"[ERROR] Could not write CSV to {args.csv}: {e}", file=sys.stderr)
            return 3
    else:
        for it in items:
            print(f"{it.position:>2}. {it.title} -- {it.url}")
            if it.snippet:
                print("   ", it.snippet[:180])

    return 0


if __name__ == "__main__":
    sys.exit(main())

अतिरिक्त पैरामीटर और एक प्रॉक्सी के साथ उपयोग का उदाहरण:

python bing_scraper.py -q "Python web scraping" --pages 3 --csv out.csv \
  --proxy "http://username:password@proxy:port"

स्क्रिप्ट क्या करती है:

  1. Bing को नियंत्रित पैरामीटरों (q, count, first) और लोकेल सेटिंग्स (cc, setlang) के साथ GET अनुरोध भेजती है।
  2. User-Agent को ओवरराइड करती है और अधिक स्थिर स्निपेट के लिए Accept-Language जोड़ती है।
  3. BeautifulSoup(..., "lxml") के माध्यम से HTML पार्स करती है, li.b_algo परिणाम कार्ड ढूंढती है, और शीर्षक, URL और स्निपेट निकालती है। BS4 में .select() CSS सेलेक्टर्स एक मानक और लचीला तरीका हैं।
  4. एक वैकल्पिक प्रॉक्सी का समर्थन करती है। Requests में सही प्रॉक्सी फ़ॉर्मेट एक प्रोटोकॉल→URL मैपिंग होता है।

स्थिरता सुझाव:

  • विराम जोड़ें (अनुरोधों के बीच अंतराल को रैंडमाइज़ करें)।
  • User-Agent घुमाएँ (डायनामिकली या अपनी सूची से)। Requests दिखाता है कि हेडर सही तरीके से कैसे सेट किए जाते हैं—हम यही तरीका कार्यशील उदाहरण में उपयोग करते हैं।
  • ज़रूरत पड़ने पर प्लेटफ़ॉर्म सीमाओं के भीतर प्रभावी स्केलिंग के लिए प्रॉक्सी इंफ़्रास्ट्रक्चर/IP रोटेशन का उपयोग करें।
  • कुल अनुरोध मात्रा को उचित रखें और CAPTCHA संकेतों के लिए प्रतिक्रियाओं की जाँच करें।
  • जटिल मामलों के लिए, प्रबंधित SERP APIs (Apify आदि) पर विचार करें जिनमें एंटीबॉट इंफ़्रास्ट्रक्चर शामिल होता है।

उपकरणों के बारे में अधिक कहाँ पढ़ें

सुझाव: यदि आपको अधिक स्थिर डेटा संग्रह के लिए प्रॉक्सी इंफ़्रास्ट्रक्चर चाहिए, तो Bing के लिए सर्वश्रेष्ठ प्रॉक्सी देखें।

Bing को स्क्रैप करते समय ब्लॉक से कैसे बचें

यह सुनिश्चित करने के मुख्य सिद्धांत कि आपका स्क्रेपर पहले चक्र में “मर” न जाए:

  • विलंब जोड़ें (अनुरोधों के बीच अंतराल को रैंडमाइज़ करें)।
  • User-Agent घुमाएँ (डायनामिकली या अपनी सूची से); हेडर सेट करने का सही तरीका दस्तावेज़ों में वर्णित है — हम अपने कार्यशील उदाहरण में वही तरीका उपयोग करते हैं।
  • सेवा की उपयोग-शर्तों का पालन करते हुए प्रॉक्सी या IP रोटेशन का उपयोग करें।
  • कुल अनुरोधों की संख्या को सीमित रखें और CAPTCHA संकेतों के लिए प्रतिक्रियाओं की निगरानी करें।
  • जटिल कार्यों के लिए, इनबिल्ट एंटीबॉट इंफ़्रास्ट्रक्चर वाले प्रबंधित SERP APIs (Apify, आदि) पर विचार करें।

निष्कर्ष

Bing को स्क्रैप करना उपयोगी है जब आप Google से आगे शोध का विस्तार करना चाहते हैं, अतिरिक्त डोनर डोमेन जुटाना चाहते हैं, वैकल्पिक SERP फीचर्स को ट्रैक करना चाहते हैं और परिदृश्य का एक स्वतंत्र दृश्य प्राप्त करना चाहते हैं। स्थिर और “आधिकारिक” एकीकरण के लिए Microsoft Azure AI Agents में Grounding with Bing Search को बढ़ावा देता है; यह सेवा-शर्तों के दृष्टिकोण से सुरक्षित है लेकिन raw JSON SERP डेटा वापस नहीं करती। यदि आपका कार्य संरचित परिणाम निकालना है, तो Requests/BS4 या Selenium के माध्यम से सीधे HTML पार्सिंग चुनें, या एक विशेष SERP API का उपयोग करें। काम के अनुसार उपकरण चुनें: प्रोटोटाइप के लिए तेज़ HTML पार्सिंग, LLM-आधारित उत्तरों के लिए एजेंट, और बड़े पैमाने पर संग्रह के लिए SERP APIs।

टिप्पणियाँ:

0 टिप्पणियाँ