[Python] trouble using playwright for data scrapping

Discussão em 'Python' iniciado por Stack, Março 24, 2025.

  1. Stack

    Stack Membro Participativo

    #This code is not getting me to scrape the articles for my scoping review. i want a summary of the 3960 articles in excel which i will transfer to EndNote

    'from playwright.sync_api import sync_playwright import csv import time import random from urllib.parse import urlparse

    def scrape_article_page(page, article_url): """Scrapes data from a single AJOL article page with enhanced reliability.""" article_data = { 'title': 'N/A', 'authors': 'N/A', 'abstract': 'N/A', 'keywords': 'N/A', 'date_published': 'N/A', 'doi': 'N/A', 'journal': 'N/A', 'issue': 'N/A', 'url': article_url }

    try:
    print(f" Navigating to: {article_url}")

    # Retry mechanism with timeout handling
    for attempt in range(3):
    try:
    page.goto(article_url, timeout=40000)
    break
    except Exception as e:
    if attempt < 2:
    print(f" Retry {attempt+1}/3 for {article_url}")
    time.sleep(2)
    else:
    print(f"❌ Failed to load {article_url}")
    return None

    # Core content detection with multiple fallbacks
    try:
    page.wait_for_selector(
    "h1.page-header, h1.article-title, section.abstract, div.article-meta",
    timeout=20000
    )
    except:
    print("⏳ Timeout waiting for article content")
    return None

    # Title extraction with priority to visible elements
    title_selector = "h1.page-header, h1.article-title, h1.title"
    title_element = page.query_selector(title_selector)
    if title_element:
    article_data['title'] = title_element.inner_text().strip()

    # Authors extraction
    author_selector = "div.authors, div.author, div.article-author"
    authors_element = page.query_selector(author_selector)
    if authors_element:
    article_data['authors'] = authors_element.inner_text().strip()

    # Abstract extraction with content validation
    abstract_selector = "section.abstract, div.abstract, div#abstract"
    abstract_element = page.query_selector(abstract_selector)
    if abstract_element:
    abstract_text = abstract_element.inner_text().strip()
    if len(abstract_text) > 50:
    article_data['abstract'] = abstract_text

    # Keyword extraction
    keyword_element = page.query_selector('meta[name="keywords"], .keywords, `your `your text`text`[class*="keyword"]')
    if keyword_element:
    if keyword_element.get_attribute('name') == 'keywords':
    article_data['keywords'] = keyword_element.get_attribute('content') or 'N/A'
    else:
    article_data['keywords'] = keyword_element.inner_text().replace('Keywords:', '').strip()

    # Publication date
    date_element = page.query_selector('[class*="date"], [class*="published"]')
    if date_element:
    article_data['date_published'] = date_element.inner_text().replace('Published:', '').strip()

    # DOI extraction
    doi_element = page.query_selector('a[href*="doi.org"], [class*="doi"], meta[name="citation_doi"]')
    if doi_element:
    article_data['doi'] = doi_element.get_attribute('href') or doi_element.get_attribute('content') or 'N/A'

    # Journal/issue information
    breadcrumbs = page.query_selector_all('nav.breadcrumbs a, .breadcrumb a, .journal-info a')
    if len(breadcrumbs) > 1:
    article_data['journal'] = breadcrumbs[1].inner_text().strip()
    if len(breadcrumbs) > 2:
    article_data['issue'] = breadcrumbs[2].inner_text().strip()

    print(f"✅ Successfully scraped: {article_url}")
    return article_data

    except Exception as e:
    print(f"❌ Critical error scraping {article_url}: {str(e)}")
    return None


    def scrape_ajol_gcs(base_url, max_pages=10): """Main scraping function with comprehensive fixes""" all_articles = []

    with sync_playwright() as p:
    browser = p.chromium.launch(
    headless=False,
    args=[
    '--disable-blink-features=AutomationControlled',
    '--disable-dev-shm-usage',
    '--no-sandbox',
    f'--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{random.randint(90,115)}.0.0.0 Safari/537.36'
    ]
    )

    context = browser.new_context(
    viewport={'width': 1920, 'height': 1080},
    java_script_enabled=True,
    locale='en-US'
    )

    page = context.new_page()

    try:
    print(" Initializing browser...")

    # Enhanced anti-detection measures
    page.add_init_script("""
    delete Object.getPrototypeOf(navigator).webdriver;
    window.chrome = {app: {isInstalled: false}};
    Object.defineProperty(navigator, 'plugins', {get: () => [1, 2, 3]});
    """)

    # Smart resource blocking
    def route_handler(route):
    blocked_resources = ['image', 'stylesheet', 'font', 'media']
    if route.request.resource_type in blocked_resources:
    route.abort()
    else:
    route.continue_()
    page.route('**/*', route_handler)

    # Navigate with error handling
    try:
    page.goto(base_url, timeout=120000)
    except Exception as e:
    print(f"❌ Initial navigation failed: {str(e)}")
    return []

    # Security check handling
    try:
    page.wait_for_selector('text="Checking your browser"', timeout=10000)
    print("⚠️ Complete security check in browser window...")
    start_time = time.time()
    while time.time() - start_time < 120: # 2 minute timeout
    if not page.is_visible('text="Checking your browser"'):
    print("✅ Security check completed")
    break
    time.sleep(5)
    else:
    print("❌ Security check timed out")
    return []
    except:
    pass

    # Search results detection
    try:
    page.wait_for_function("""() => {
    const resultsContainer = document.querySelector('.gsc-results') ||
    document.querySelector('.gsc-wrapper') ||
    document.querySelector('.gs-result');
    return resultsContainer && resultsContainer.children.length > 0;
    }""", timeout=60000)
    print(" Search results loaded")
    except:
    print("❌ Search results failed to load")
    page.screenshot(path='debug_search_failure.png')
    return []

    # Get results using multiple selectors
    results = page.locator(".gsc-webResult.gsc-result, .gsc-result, .gs-result")
    if results.count() == 0:
    print("⚠️ No results found with combined selectors")
    return []

    print(f" Found {results.count()} articles")

    current_page = 1
    while current_page <= max_pages:
    print(f"\n Processing page {current_page}/{max_pages}")

    # Process articles
    for i in range(results.count()):
    try:
    result = results.nth(i)
    link = result.locator("a[data-ctorig], a.gs-title").first
    article_url = link.evaluate("""
    el => el.getAttribute('data-ctorig') || el.href
    """)

    if not article_url or "/download/" in article_url:
    print(f"⚠️ Skipping invalid/download link: {article_url}")
    continue

    print(f" Processing article {i+1}/{results.count()}")

    # Open in new tab with middle-click simulation
    with context.expect_page(timeout=15000) as new_page_info:
    link.dispatch_event('click', button="middle")
    article_page = new_page_info.value

    # Scrape article data
    try:
    article_page.wait_for_load_state('networkidle', timeout=20000)
    article_data = scrape_article_page(article_page, article_url)
    finally:
    article_page.close()

    if article_data:
    all_articles.append(article_data)

    time.sleep(random.uniform(1, 3))

    except Exception as e:
    print(f"⚠️ Error processing article {i+1}: {str(e)}")
    continue

    # Enhanced pagination handling
    try:
    next_btn = page.locator("div.gsc-cursor-next-page:visible").first
    if next_btn.is_enabled():
    print("⏩ Clicking next page")
    next_btn.click()
    # Wait for new results to load
    page.wait_for_function("""() => {
    const oldCount = arguments[0];
    const newCount = document.querySelectorAll('.gsc-webResult.gsc-result').length;
    return newCount !== oldCount;
    }""", args=[results.count()], timeout=30000)
    current_page += 1
    time.sleep(2)
    # Refresh results locator
    results = page.locator(".gsc-webResult.gsc-result, .gsc-result, .gs-result")
    else:
    print("⏹ No more pages available")
    break
    except Exception as e:
    print(f"⛔ Pagination failed: {str(e)}")
    break

    finally:
    browser.close()

    return all_articles


    def save_to_csv(articles, filename): """Saves data to CSV with error handling""" if not articles: print(" No articles to save") return

    try:
    with open(filename, "w", newline="", encoding="utf-8") as csvfile:
    fieldnames = ["title", "authors", "abstract", "keywords",
    "date_published", "doi", "journal", "issue", "url"]
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(articles)
    print(f" Saved {len(articles)} articles to {filename}")
    except Exception as e:
    print(f"❌ CSV save failed: {str(e)}")


    if name == "main": # IMPORTANT: Verify this URL matches EXACTLY what's in your browser SEARCH_URL = ( "https://www.ajol.info/index.php/ajol/Gsearch/google?q=%22HIV%22+OR+%22Human+Immunodeficiency+Virus%22%29+AND+%28%22People+living+with+HIV%22+OR+PLHIV+OR+%22HIV-positive+persons%22+OR+%22HIV+infected+persons%22+OR+%22HIV+patients%22+OR+%22HIV+positive+individuals%22+OR+%22AIDS+patients%22+OR+%22Communities+of+PLHIV%22+OR+PLWHA+OR+%22HIV+peers%22%29+AND+%28involvement+OR+engagement+OR+participation+OR+%22community+participation%22+OR+%22patient+involvement%22+OR+%22community+engagement%22+OR+%22decision-making%22+OR+%22policy+development%22+OR+%22program+implementation%22+OR+%22monitoring+and+evaluation%22+OR+%22peer+support%22+OR+advocacy+OR+%22health+promotion%22+OR+%22capacity+building%22+OR+empowerment#gsc.tab=0&gsc.page=1" )

    # Configuration
    MAX_PAGES = 1 # Start with 1 page for testing
    HEADLESS_MODE = False # Keep browser visible for debugging

    articles = scrape_ajol_gcs(SEARCH_URL, max_pages=MAX_PAGES)
    save_to_csv(articles, "ajol_articles.csv")


    `

    Continue reading...

Compartilhe esta Página