【问题标题】:Python 3.x Beautifulsoup crawling image urlPython 3.x Beautifulsoup 抓取图片网址
【发布时间】:2017-04-06 12:33:13
【问题描述】:

我正在尝试使用 Python 进行图像 URL 抓取

用开发工具确认谷歌图片搜索窗口的结果,大约有100个图片网址

更多网址会向下滚动。不过没关系。

问题是我只有 20 个 URL。

我在一个 html 文件中打开了一个可寻址的请求。

我确认那里只有 20 个 URL。

我认为请求中只有20个图片URL,所以只输出了20个。

如何获取所有图片的 URL?

这是源代码。

#-*- coding: utf-8 -*-
import urllib.request
from bs4 import BeautifulSoup

if __name__ == "__main__":
    print("Crawling!!!!!!!!!!!!!!!")

    hdr = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0)', 
           'referer' : 'http:google.com',
           'Accept': 'text/html',
           'Accept':'application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
           'Accept': 'none',
           'Connection': 'keep-alive'}

    inputSearch = "sites:pinterest+white+jeans"
    req = urllib.request.Request("https://www.google.co.kr/searchhl=ko&site=imghp&tbm=isch&source=hp&biw=1600&bih=770&q=" + inputSearch, headers = hdr)
    data = urllib.request.urlopen(req).read()

    bs = BeautifulSoup(data, "html.parser")

    for img in bs.find_all('img'):
        print(img.get('src'))

【问题讨论】:

  • 链接对我来说似乎是不正确的https://www.google.co.kr/searchhl=ko&site=imghp&tbm=isch&source=hp&biw=1600&bih=770&q=,请问您的查询具体是什么

标签: python-3.x beautifulsoup


【解决方案1】:

您的链接错误。您可以使用以下代码,看看它是否符合您的需求。

您只需传递一个searchTerm,程序就会打开谷歌页面并获取 20 张图片的网址。

代码:

def get_images_links(searchTerm):

    import requests
    from bs4 import BeautifulSoup

    searchUrl = "https://www.google.com/search?q={}&site=webhp&tbm=isch".format(searchTerm)
    d = requests.get(searchUrl).text
    soup = BeautifulSoup(d, 'html.parser')

    img_tags = soup.find_all('img')

    imgs_urls = []
    for img in img_tags:
        if img['src'].startswith("http"):
            imgs_urls.append(img['src'])

    return(imgs_urls)

用法:

get_images_links('computer')

输出:

['https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSeq5kKIsOg6zSM2bSrWEnYhpZEpmOYiiLzqf6qfwKzSVUoZ5rHoya75DM',
 'https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTBUesIhyt4CgASIUDruqvvMzUBFCuG_iV92NXjZPMtPE5v2G626bge0g0',
 'https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcRYz8c6LUAiyuAsXkMrOH8DC56aFEMy63m8Fw8-ZdutB5EDpw1hl0y3xg',
 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT33QNycX0Ghqhfqs7Masrk9uvp6d66VlD2djHFfqL4P6phZCJLxkSx0wnt',
 'https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcRUF11cLRzH2WNfiUJ3WeAOm7Veme0_GLfwoOCs3R5GTQDfcFHMgsNQlyo',
 'https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTxcTcv4NPTboVorbD4I-uJbYjY4KjAR5JaMvUXCg33CLDUqop8IufKNw',
 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTU8MkWwhDgcobqn_H2N3SS7dPVwu3I-ki1Sa_4u5YOEt-rAfOk1Kb2jpHO',
 'https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQlGu_Y_dhu60UNyilmIUSuOjX5_UnmcWr2AXGJ0w6BmvCXUZissCrtPcw',
 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQN7ItGvBHD1H9EMBC0ZFDMzNu5nt2L-EK1CKmQE4gRNtylalyTTJQxalY',
 'https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcQyFgwD4Wr20OImzk9Uc0gGGI2-7mYQAU6mJn2GEFkpgLTAqUQUm4KL0TUQwQ',
 'https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQR0LFRaUGIadOO5_qolg9ZWegXW0OTghzBf1YzoIhpqkaiY1f3YNx4JnE',
 'https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcRuOk4nPPPaUdjnZl1pEwGwlfq25GjvZFsshmouB0QaV925KxHg43wJFWc6',
 'https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcR5aqLfB9SaFBALzp4Z2qToLeWqeUjqaS3EwNhi6faHRCxYCPMsjhmivKf8',
 'https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcR6deLi7H9DCaxJXJyP7lmoixad5Rgo1gBLfVQ35lEWrvpgPoyQJ8CcZ-4',
 'https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcSPQAfl2WB-AwziLan6NAzvzh2xVDu_XJEcjqSGOdnOJdffo7goWhrFd3wU',
 'https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcSB3o5cP8DMk9GqT9wpB1N7q6JtREUwitghlXO65UD5s3xCoLj80QuDlzw',
 'https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcQ18lWMvzZcIZvKI36BUUpnBIaa5e4A3TUAVdxAs6hhJ-rod446dMrPph2V',
 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR8XZhvomXcafQehhetM1_ZXOufBvWmEDAbOsqX-fiU5Xu3U6uWAO3XW-M',
 'https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQiWudrcl9y0XbtC19abcPfSwO4N060ipv4znqxnpLYWX5UFO-QdzJatd0r',
 'https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQtgqDxef3AOsiyUk0J0MbXgZT8c0JsAW3UpoumSTMFSGXde3BETrGSqw']

编辑:

如果你想获取超过20个url,你必须想办法发送ajax请求来获取页面的其余部分,或者你可以使用selenium来模拟你和网页的交互。

我使用了第二种方法(可能还有很多其他方法可以做到这一点,如果您愿意,可以对这段代码进行大量优化):

代码2:

def scrape_all_imgs_google(searchTerm):

    from selenium import webdriver
    from bs4 import BeautifulSoup
    from time import sleep

    def scroll_page():
        for i in range(7):
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
            sleep(3)

    def click_button():
        more_imgs_button_xpath = '//*[@id="smb"]'
        driver.find_element_by_xpath(more_imgs_button_xpath).click()   

    def create_soup():
        html_source = driver.page_source
        soup = BeautifulSoup(html_source, 'html.parser')

    def find_imgs():
        imgs_urls = []
        for img in soup.find_all('img'):
            try:
                if img['src'].startswith('http'):
                    imgs_urls.append(img['src'])
            except:
                pass

    #create webdriver
    driver = selenium.webdriver.Chrome()

    #define url using search term
    searchUrl = "https://www.google.com/search?q={}&site=webhp&tbm=isch".format(searchTerm)

    #get url
    driver.get(searchUrl)

    try:
        click_button()
        scroll_page()
    except:
        scroll_page()
        click_button()   

    #create soup only after we loaded all imgs when we scroll'ed the page down
    create_soup()

    #find imgs in soup
    find_imgs()

    #close driver
    driver.close()

    #return list of all img urls found in page
    return imgs_urls    

用法:

urls = scrape_all_imgs_google('computer')

print(len(urls))
print(urls)

输出:

377
['https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcT5Hi9cdE5JPyGl6G3oYfre7uHEie6zM-8q3zQOek0VLqQucGZCwwKGgfoE', 'https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcR0tu_xIYB__PVvdH0HKvPd5n1K-0GVbm5PDr1Br9XTyJxC4ORU5e8BVIiF', 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQqHh6ZR6k-7izTfCLFK09Md19xJZAaHbBafCej6S30pkmTOfTFkhhs-Ksn', and etc...

如果您不想使用此代码,可以查看Google Scraper,看看它是否有任何对您有用的方法。

【讨论】:

  • 谢谢。但我想获得超过 20 个的 URL,我该怎么办?
  • @안진환 我已经更新了我的答案。看看新功能:scrape_all_imgs_google(searchTerm).
  • @안진환 很高兴能为您提供帮助!欢迎来到 StackOverflow。如果我的回答解决了您的问题,您可以mark it as accepted 结束您的问题。
  • 谢谢我知道如何结束我的问题。我想问最后一个问题。向下滚动后没有按下更多图像按钮我认为它似乎没有异常处理如何设置不再向下滚动时按下按钮的条件?
  • 哦,我解决了。按下按钮然后完成我添加一行 scroll_page() 来尝试语句
【解决方案2】:

要获得超过 20 个图像链接,您可以使用 ijn URL 参数,例如,ijn=0 表示 100 个图像,ijn=1 表示 200 个图像,依此类推,您无需使用 selenium 即可实现此目的。

要使用requests 和beautifulsoup 抓取全分辨率图像URL,您需要通过regex 从页面源代码中抓取数据。

查找所有<script>标签:

soup.select('script')

通过regex匹配<script>标签中的图片数据:

matched_images_data = ''.join(re.findall(r"AF_initDataCallback\(([^<]+)\);", str(all_script_tags)))

通过来自 JSON 字符串的 regex 匹配所需的图像(在这种情况下为全分辨率):

# https://kodlogs.com/34776/json-decoder-jsondecodeerror-expecting-property-name-enclosed-in-double-quotes
# if you try to json.loads() without json.dumps() it will throw an error: "Expecting property name enclosed in double quotes"
matched_images_data_fix = json.dumps(matched_images_data)
matched_images_data_json = json.loads(matched_images_data_fix)

matched_google_image_data = re.findall(r'\[\"GRID_STATE0\",null,\[\[1,\[0,\".*?\",(.*),\"All\",', 
                                                    matched_images_data_json)

# ...

matched_google_full_resolution_images = re.findall(r"(?:'|,),\[\"(https:|http.*?)\",\d+,\d+\]",
                                                    matched_google_image_data)

使用bytes() 和decode() 提取和解码它们:

for fixed_full_res_image in matched_google_full_resolution_images:
    original_size_img_not_fixed = bytes(fixed_full_res_image, 'ascii').decode('unicode-escape')
    original_size_img = bytes(original_size_img_not_fixed, 'ascii').decode('unicode-escape')

用于抓取和下载全分辨率图像的代码和full example in the online IDE:

import requests, lxml, re, json
from bs4 import BeautifulSoup


headers = {
    "User-Agent":
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19582"
}

params = {
    "q": "pexels cat",
    "tbm": "isch", 
    "hl": "en",
    "ijn": "0",
}

html = requests.get("https://www.google.com/search", params=params, headers=headers)
soup = BeautifulSoup(html.text, 'lxml')


def get_images_data():

    print('\nGoogle Images Metadata:')
    for google_image in soup.select('.isv-r.PNCib.MSM1fd.BUooTd'):
        title = google_image.select_one('.VFACy.kGQAp.sMi44c.lNHeqe.WGvvNb')['title']
        source = google_image.select_one('.fxgdke').text
        link = google_image.select_one('.VFACy.kGQAp.sMi44c.lNHeqe.WGvvNb')['href']
        print(f'{title}\n{source}\n{link}\n')

    # this steps could be refactored to a more compact
    all_script_tags = soup.select('script')

    # # https://regex101.com/r/48UZhY/4
    matched_images_data = ''.join(re.findall(r"AF_initDataCallback\(([^<]+)\);", str(all_script_tags)))
    
    # https://kodlogs.com/34776/json-decoder-jsondecodeerror-expecting-property-name-enclosed-in-double-quotes
    # if you try to json.loads() without json.dumps it will throw an error:
    # "Expecting property name enclosed in double quotes"
    matched_images_data_fix = json.dumps(matched_images_data)
    matched_images_data_json = json.loads(matched_images_data_fix)

    # https://regex101.com/r/pdZOnW/3
    matched_google_image_data = re.findall(r'\[\"GRID_STATE0\",null,\[\[1,\[0,\".*?\",(.*),\"All\",', matched_images_data_json)

    # https://regex101.com/r/NnRg27/1
    matched_google_images_thumbnails = ', '.join(
        re.findall(r'\[\"(https\:\/\/encrypted-tbn0\.gstatic\.com\/images\?.*?)\",\d+,\d+\]',
                   str(matched_google_image_data))).split(', ')

    print('Google Image Thumbnails:')  # in order
    for fixed_google_image_thumbnail in matched_google_images_thumbnails:
        # https://stackoverflow.com/a/4004439/15164646 comment by Frédéric Hamidi
        google_image_thumbnail_not_fixed = bytes(fixed_google_image_thumbnail, 'ascii').decode('unicode-escape')

        # after first decoding, Unicode characters are still present. After the second iteration, they were decoded.
        google_image_thumbnail = bytes(google_image_thumbnail_not_fixed, 'ascii').decode('unicode-escape')
        print(google_image_thumbnail)

    # removing previously matched thumbnails for easier full resolution image matches.
    removed_matched_google_images_thumbnails = re.sub(
        r'\[\"(https\:\/\/encrypted-tbn0\.gstatic\.com\/images\?.*?)\",\d+,\d+\]', '', str(matched_google_image_data))

    # https://regex101.com/r/fXjfb1/4
    # https://stackoverflow.com/a/19821774/15164646
    matched_google_full_resolution_images = re.findall(r"(?:'|,),\[\"(https:|http.*?)\",\d+,\d+\]",
                                                       removed_matched_google_images_thumbnails)


    print('\nDownloading Google Full Resolution Images:')  # in order
    for index, fixed_full_res_image in enumerate(matched_google_full_resolution_images):
        # https://stackoverflow.com/a/4004439/15164646 comment by Frédéric Hamidi
        original_size_img_not_fixed = bytes(fixed_full_res_image, 'ascii').decode('unicode-escape')
        original_size_img = bytes(original_size_img_not_fixed, 'ascii').decode('unicode-escape')
        print(original_size_img)


get_images_data()


-------------
'''
Google Images Metadata:
9,000+ Best Cat Photos · 100% Free Download · Pexels Stock Photos
pexels.com
https://www.pexels.com/search/cat/
...

Google Image Thumbnails:
https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR2cZsuRkkLWXOIsl9BZzbeaCcI0qav7nenDvvqi-YSm4nVJZYyljRsJZv6N5vS8hMNU_w&usqp=CAU
...

Full Resolution Images:
https://images.pexels.com/photos/1170986/pexels-photo-1170986.jpeg?cs=srgb&dl=pexels-evg-culture-1170986.jpg&fm=jpg
https://images.pexels.com/photos/3777622/pexels-photo-3777622.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500
...
'''

或者,您可以使用来自 SerpApi 的 Google Images API 来实现相同的目的。这是一个带有免费计划的付费 API。

您的情况的不同之处在于,您不必处理regex 来匹配并从页面的源代码中提取所需的数据,相反,您只需要遍历结构化 JSON 并获得您想要的.

要集成的代码:

import os, json # json for pretty output
from serpapi import GoogleSearch


def get_google_images():
    params = {
      "api_key": os.getenv("API_KEY"),
      "engine": "google",
      "q": "pexels cat",
      "tbm": "isch"
    }

    search = GoogleSearch(params)
    results = search.get_dict()

    print(json.dumps(results['images_results'], indent=2, ensure_ascii=False))


get_google_images()

---------------
'''
[
...
  {
    "position": 100, # img number
    "thumbnail": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRR1FCGhFsr_qZoxPvQBDjVn17e_8bA5PB8mg&usqp=CAU",
    "source": "pexels.com",
    "title": "Close-up of Cat · Free Stock Photo",
    "link": "https://www.pexels.com/photo/close-up-of-cat-320014/",
    "original": "https://images.pexels.com/photos/2612982/pexels-photo-2612982.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
    "is_product": false
  }
]
'''

P.S - 我写了一篇关于如何抓取 Google Images 和 how to reduce chance of being blocked while web scraping search engines 的更深入的博文。

免责声明,我为 SerpApi 工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-25
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    • 1970-01-01
    • 1970-01-01
    • 2018-04-25
    • 2014-06-20
    相关资源
    最近更新 更多