【问题标题】:Python Webscraping - Unable to get element with URL parsing functionPython Web Scraping - 无法使用 URL 解析功能获取元素
【发布时间】:2021-08-10 05:51:58
【问题描述】:

这是我写的抓取代码。

import sys
import time
from time import sleep
from selenium import webdriver
from selenium.common import exceptions
from tqdm import tqdm

Max_Page = 2


def open_webdriver():
    options = webdriver.ChromeOptions()
    options.add_argument('headless')
    driver = webdriver.Chrome(r'c:\chromedriver\chromedriver.exe', options=options)
    return driver


def get_result(title, link, price):
    result = (title, link, price)
    return result


def get_url(search_term, page):
    base_template = f'https://shopee.com.my/search?keyword={search_term}'
    base_url = base_template.format(search_term)
    url_template = base_url + '&page={}'
    if page == 0:
        return base_url
    else:
        return url_template.format(page)
    return url_template.format(page)


def time_interval():
    from random import random
    time_in_seconds = random() * 2
    sleep(time_in_seconds)


def spider(search_term):
    num_records_scraped = 0

    for page in range(0, Max_Page):
        driver = open_webdriver()

        search_url = get_url(search_term, page)
        driver.get(search_url)
        print(search_url)
        # search_url = f'https://shopee.ph/search?keyword={search_term}&page={page}'
        time.sleep(1)
        # Page Scroll
        y = 100
        for timer in tqdm(range(0, 6), file=sys.stdout):
            driver.execute_script("window.scrollTo(0, " + str(y) + ")")
            y += 700
            time.sleep(1)
        items = driver.find_elements_by_xpath('//div[@data-sqe="item"]')

        for item in items:
            try:
                title = item.find_element_by_xpath('.//a/div/div/div[2]/div[1]/div/div').text
            except exceptions.NoSuchElementException:
                continue

            try:
                link = item.find_element_by_xpath('.//a').get_attribute('href')
            except exceptions.NoSuchElementException:
                continue

            try:
                price_temp = item.find_element_by_xpath('.//a/div/div/div[2]/div[2]/div/span[2]').text
                price = "₱" + price_temp
            except exceptions.NoSuchElementException:
                continue

            record = get_result(title, link, price)
            print(record)

            if record:
                get_records.append(record)
                num_records_scraped += 1

        time_interval()

    driver.quit()


if __name__ == '__main__':
    get_records = []
    spider('ipad')

输出

上面的代码不会得到标题项。但是,如果我提供直接 URL,它会起作用。

def spider(search_term):
    num_records_scraped = 0

    for page in range(0, Max_Page):
        driver = open_webdriver()
        # search_url = get_url(search_term, page)
        search_url = f'https://shopee.ph/search?keyword={search_term}&page={page}'
        driver.get(search_url)
        print(search_url)
        time.sleep(1)
        # Page Scroll
        y = 100
        for timer in tqdm(range(0, 6), file=sys.stdout):
            driver.execute_script("window.scrollTo(0, " + str(y) + ")")
            y += 700
            time.sleep(1)
        items = driver.find_elements_by_xpath('//div[@data-sqe="item"]')

        for item in items:
            try:
                title = item.find_element_by_xpath('.//a/div/div/div[2]/div[1]/div/div').text
            except exceptions.NoSuchElementException:
                continue

            try:
                link = item.find_element_by_xpath('.//a').get_attribute('href')
            except exceptions.NoSuchElementException:
                continue

            try:
                price_temp = item.find_element_by_xpath('.//a/div/div/div[2]/div[2]/div/span[2]').text
                price = "₱" + price_temp
            except exceptions.NoSuchElementException:
                continue

            record = get_result(title, link, price)
            print(record)

            if record:
                get_records.append(record)
                num_records_scraped += 1

        time_interval()

    driver.quit()

区别是

 # search_url = get_url(search_term, page)
   search_url = f'https://shopee.ph/search?keyword={search_term}&page={page}'

输出

所以获取url函数有问题,但不知道是什么问题。

def get_url(search_term, page):
    base_template = f'https://shopee.com.my/search?keyword={search_term}'
    base_url = base_template.format(search_term)
    url_template = base_url + '&page={}'
    if page == 0:
        return base_url
    else:
        return url_template.format(page)
    return url_template.format(page)

我已经验证了URL站点结果是一样的,

https://shopee.com.my/search?keyword=ipad

https://shopee.com.my/search?keyword=ipad&page=0

【问题讨论】:

    标签: python web-scraping


    【解决方案1】:

    我认为你可以用这种简单的方式重新定义你的函数:

       def get_url(search_term, page):
            if page == 0:
              url_to_scrape = f'https://shopee.com.my/search?keyword={search_term}'
            else:
              url_to_scrape = f'https://shopee.com.my/search?keyword={search_term}&page={page}'
            return url_to_scrape
    

    无论如何,我尝试使用 requests + beautifulsoup 并没有收到任何错误。

    import requests
    
    r  = requests.get(get_url('IPAD',0))
    

    输出:<Response [200]>

    试图从页面获取所有hfrefs

    from bs4 import BeautifulSoup
    for a in soup.find_all(href=True):
        print("Found the URL:", a['href'])
    

    结果:

    Found the URL: //cf.shopee.com.my/
    Found the URL: //deo.shopeemobile.com/shopee/
    Found the URL: //cv.shopee.com.my/
    Found the URL: https://deo.shopeemobile.com/shopee/shopee-mobilemall-live-sg/assets/entry-modules.f955bbd094df60279329.css
    Found the URL: https://deo.shopeemobile.com/shopee/shopee-mobilemall-live-sg/assets/bundle.672370fb126ccc7e06e2.css
    Found the URL: /m/assets/manifest.64961108192778c454d263d59ac73576.json
    Found the URL: https://deo.shopeemobile.com/shopee/shopee-mobilemall-live-sg/assets/ios_icon_120x120.9c9cd4366011639d86dcf03856866b39.png
    Found the URL: https://deo.shopeemobile.com/shopee/shopee-mobilemall-live-sg/assets/ios_icon_180x180.350d4cdc7ba40b87541691005bda74c5.png
    Found the URL: https://deo.shopeemobile.com/shopee/shopee-mobilemall-live-sg/assets/ios_splash_screen_640x1136.44f3b1919faea215b1e8a8f33bc85eb2.png
    

    编辑:

    查看浏览器网络选项卡中的响应。该站点公开了一个 API 服务。

    import requests
    import json
    
    r = requests.get('https://shopee.com.my/api/v4/search/search_items?by=relevancy&keyword=IPAD&limit=60&newest=0&order=desc&page_type=search&scenario=PAGE_GLOBAL_SEARCH&version=2')
    
    # get json from site
    json_data = json.loads(str(r.content, encoding='utf-8'))
    # iterate over 'items'
    for i in json_data['items']:
        print(i['item_basic']['name'])
    

    结果:

    iPad Air 4th Generation, Wi-Fi
    iPad Air (4th Generation) WiFi
    Apple 11-inch iPad Pro (M1, 2021) - Wi-Fi
    Apple 12.9-inch iPad Pro (M1, 2021) - Wi-Fi
    iPad Air (4th Generation) WiFi + Cellular
    Apple 11-inch iPad Pro Wi-Fi (M1, 2021 New) Free Shipping
    Apple 12.9-inch iPad Pro Wi-Fi (M1, 2021 New) Free Shipping
    iPad Air 4th Generation, Wi-Fi + Cellular
    Apple iPad Pro 12.9-inch (5th generation) WiFi + Cellular
    Apple iPad Pro 12.9-inch (4th generation) WiFi + Cellular
    Original Ipad air 2 WIFI +CELLULAR (Secondhand 95% Condition)
    Ipad 7th 8th Air 4 Pro 11  Ipad 9.7 2017 2018 Ipad 10.5 Air Air 2 Air 3 Ipad 2 3 4 Mini 1 2 3 4 5 HD Clear Tempered Glas
    Apple 10.9" iPad Air 4th Generation (64GB / 256GB)
    [100% Original] iPad Pro (12.9-Inch) Used Set Look As New
    

    【讨论】:

    • 感谢您的回答,但是当我使用您的 url 函数时,它具有相同的行为。顺便说一句,我可以用我的代码获得href,价格,标题除外。我不能只得到标题元素。那是我的问题。
    • 如果你不能只抓取“title”,这意味着你的代码有错误(title = item.find_element_by_xpath('.//a/div/div/div[2] /div[1]/div/div').text)
    • 还要记住 TRY> EXCEPT > CONTINUE 是一种不好的做法。如果你没有发现错误,你将无法调试/改进你的代码。
    • 如果我的获取元素代码有错误怎么办 - title (title = item.find_element_by_xpath('.//a/div/div/div[2]/div[1]/div/div') .text) - 然后即使我用 search_url = f'shopee.ph/search?keyword={search_term}&page={page}' 替换了 url,我也不会得到标题,但事实并非如此。那是我的问题。
    • 哦,对我很有帮助。一个问题,如何使用您的代码通过 json_data 获取 href 链接? for i in json_data['items']: print(i['item_basic']['name']),当我查看 url 时,我可以看到 json 响应但我找不到 href 链接。
    【解决方案2】:

    只是为了解决问题,您确定该网站允许网络抓取吗?

    要检查网站是否允许网页抓取,您可以使用 status_code 如下:

    导入请求

    从 bs4 导入 BeautifulSoup

    r=requests.get("请输入您选择的 URL")

    r.status_code

    此输出应为 200。除 200 之外的任何值都表示您尝试抓取的网站要么不允许网页抓取,要么部分允许。

    【讨论】:

    • 期待您安装了 bs4。
    • 哦,我对我的原始代码使用响应检查。上面的代码,它只是问题的一部分。谢谢。
    【解决方案3】:

    由于该页面是由 JavaScript 加载的,因此我使用 selenium 运行 javascript 并获取其源代码。

    之后,我使用beautifulsoup 将源代码转换为soup。一旦你有了soup,就很容易得到你需要的数据。

    我的代码为这两个页面提供了相同的结果

    此代码将打印每个项目的titleslinks

    import bs4 as bs
    import time
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    
    url = 'https://shopee.com.my/search?keyword=ipad'
    options = Options()
    options.add_argument("--headless")
    driver = webdriver.Chrome(options=options)
    time.sleep(3)
    driver.get(url)
    html = driver.page_source
    
    soup = bs.BeautifulSoup(html, 'lxml')
    divs = soup.findAll('div', class_='col-xs-2-4 shopee-search-item-result__item')
    #print(len(divs))
    
    for div in divs:
        anchor = div.find('a')
        name = div.find('div', class_='yQmmFK _1POlWt _36CEnF')
        if anchor is not None and name is not None:
            link = anchor['href']
            title = name.text.strip()
            print(f'({title}, {link})')
    
    
    Sample Output:
    
    (IPad 9.7 2017/2018 Air Air2 IPad gen 7/8 10.2 Mini 1 2 3 4 5 Slim Smart Case Flexible Soft Silicone Soft Back Cover, /IPad-9.7-2017-2018-Air-Air2-IPad-gen-7-8-10.2-Mini-1-2-3-4-5-Slim-Smart-Case-Flexible-Soft-Silicone-Soft-Back-Cover-i.324014372.3262579361?ads_keyword=ipad%2010%202%20case&adsid=10522606&campaignid=5819106&position=0)
    (I_PAD (8th GENE) 128GB Wi-Fi USED SET, /I_PAD-(8th-GENE)-128GB-Wi-Fi-USED-SET-i.8946535.10322462597?ads_keyword=ipad%208&adsid=26912611&campaignid=15428055&position=1)
    (Bluetooth keyboard, wireless mouse, easy to connect Easy to carry, use for computers, for iPad, tablets, mobile phones., /Bluetooth-keyboard-wireless-mouse-easy-to-connect-Easy-to-carry-use-for-computers-for-iPad-tablets-mobile-phones.-i.400069365.8028051395?ads_keyword=ipad&adsid=16603522&campaignid=9235869&position=2)
    .
    .
    .
    

    【讨论】:

    • 这个网站是由大量的 JavaScript 制作的,但幸运的是,它公开了漂亮的 API。所以我们不需要 Selenium。
    猜你喜欢
    • 2019-06-03
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    • 2021-11-17
    • 1970-01-01
    • 1970-01-01
    • 2021-09-16
    • 1970-01-01
    相关资源
    最近更新 更多