49

I want get captcha image from browser. I have got a url of this picture, but the this picture changes each updated time (url is constant).

Is there any solution to get picture from browser (like 'save picture as' button)?

From the other hand, I think it should be work:

  1. get screenshot of the browser
  2. get position of picture
  3. crop captcha from screenshot using opencv

link of the dynamic capcha - link

The problem was solved via screenshot:

browser.save_screenshot('screenshot.png')
img = browser.find_element_by_xpath('//*[@id="cryptogram"]')
loc = img.location

image = cv.LoadImage('screenshot.png', True)
out = cv.CreateImage((150,60), image.depth, 3)
cv.SetImageROI(image, (loc['x'],loc['y'],150,60))
cv.Resize(image, out)
cv.SaveImage('out.jpg', out)

Thanks

alecxe
  • 441,113
  • 110
  • 1,021
  • 1,148
user1941407
  • 2,505
  • 3
  • 23
  • 38
  • do you want a snapshot of the browser or a certain image from the page – Serial Jun 28 '13 at 09:46
  • I need captcha image from the page. Snapshoot is a way to get it. – user1941407 Jun 28 '13 at 13:55
  • what is the module 'cv' ?, nevermind--see: opencv – brizz Jan 03 '15 at 01:47
  • 1
    @erm3nda, apparently you don't know how to read past commas or understand dates. – brizz Jun 08 '15 at 22:21
  • What i don't know is the need of put here "hey i don't know X when you can search it instead". What's your real profit of doing that? Please, watch my next comment and say me what do you think about. – m3nda Jun 08 '15 at 22:27
  • whats "find_element_by_xpath"? nevermind-see: find_element_by_xpath. – m3nda Jun 08 '15 at 22:27
  • And 'cv' commas content is assumed to be the words that the user used when created the opencv instance. The same thing when you create a new Selenium webdriver object. – m3nda Jun 08 '15 at 22:30
  • Check this https://stackoverflow.com/a/54986819/7484554 – Super Mario Mar 04 '19 at 16:38

5 Answers5

62

Here's a complete example (using google's recaptcha as a target):

import urllib
from selenium import webdriver

driver = webdriver.Firefox()
driver.get('http://www.google.com/recaptcha/demo/recaptcha')

# get the image source
img = driver.find_element_by_xpath('//div[@id="recaptcha_image"]/img')
src = img.get_attribute('src')

# download the image
urllib.urlretrieve(src, "captcha.png")

driver.close()

UPDATE:

The problem with dynamic generated images is that there is a new image generated each time you request it. In that case, you have several options:

  • take a screenshot

    from selenium import webdriver
    
    driver = webdriver.Firefox()
    driver.get('https://moscowsg.megafon.ru/ps/scc/php/cryptographp.php?PHPSESSID=mfc540jkbeme81qjvh5t0v0bnjdr7oc6&ref=114&w=150')
    
    driver.save_screenshot("screenshot.png")
    
    driver.close()
    
  • simulate right click + "Save As". See this thread for more info.

Hope that helps.

Community
  • 1
  • 1
alecxe
  • 441,113
  • 110
  • 1,021
  • 1,148
  • 1
    google recapcha has static url. [link](http://www.google.com/recaptcha/api/image?c=03AHJ_Vusche6ZKC-el4YRHCYA97fvqPZYG8P11X3G4_ZsTSzOA0dEjCJil0oipRTTg88RedIGzvPjTqy1Ufq2s7nEs7u_2ZIJUE5uyzZevtCXqFDJTvMwZZGS8gUqkiDQgvFhNqvjkdRumsGuJwvBOujpEZcUSS62kLGFxYRI1puGd4EvrpCV3yg) – user1941407 Jun 28 '13 at 10:36
  • Then, give a link where it's dynamic. – alecxe Jun 28 '13 at 10:36
  • 1
    link of the capcha - [link](https://moscowsg.megafon.ru/ps/scc/php/cryptographp.php?PHPSESSID=mfc540jkbeme81qjvh5t0v0bnjdr7oc6&ref=114&w=150) – user1941407 Jun 28 '13 at 10:38
  • Additionally, could you provide a link to the whole page with captcha? – alecxe Jun 28 '13 at 11:01
  • [link](https://moscowsg.megafon.ru/) I save problem via screenshot. It is not efficient, but works. See head question – user1941407 Jun 28 '13 at 16:38
  • @alecxe,thanks for your post, i simulated your code and it worked for me, can you please tell me how did figure out the xpath for the image ('//div[@id="recaptcha_image"]/img') , thanks alot – fooBar Sep 12 '13 at 13:51
  • 13
    In the last couple of years.. urllib has changed. Instead of using urllib.urlretrieve, you now need to use urllib.request.urlretrieve. – zwep Jul 24 '17 at 06:40
  • 3
    can selenium itself download the image in the same session inside the automated browser? – Rahul Bali Jan 14 '18 at 20:21
  • to use urllib.request.urlretrieve first import urllib.request otherwise it will throw error – Adarsh Patel Feb 06 '20 at 22:16
  • 3
    this will _not_ work if accessing the image requires authentication – ccpizza Mar 10 '22 at 21:50
23

It's ok to save a screenshot from the whole page and then cut the image from, but you can also to use the "find" method from "webdriver" to locate the image you want to save, and write the "screenshot_as_png" property like below:

from selenium import webdriver
driver = webdriver.Firefox()
driver.get('https://www.webpagetest.org/')
with open('filename.png', 'wb') as file:
    file.write(driver.find_element_by_xpath('/html/body/div[1]/div[5]/div[2]/table[1]/tbody/tr/td[1]/a/div').screenshot_as_png)

Sometimes it could get an error because of the scroll, but depending on your necessity, it's a good way to get the image.

Suraj Kumar
  • 5,366
  • 8
  • 19
  • 39
Ramon
  • 241
  • 2
  • 3
  • @ Ramon this does not work, I am trying to get the image of your profile pic from this page and get the error `elenium.common.exceptions.WebDriverException: Message: unknown command: session/5734e4b0f8d6171317af42ddf0979562/element/0.9586500909174849-1/screenshot` – Jortega Jan 20 '20 at 21:32
  • So, @Jortega. Try sending your code here, then I can check if I find same mistake. – Ramon Jan 22 '20 at 12:09
  • 1
    Interesting answer! – keramat Aug 27 '20 at 09:56
  • But what if the image is a gif? Is there anyway get download that gif file? – oeter May 27 '22 at 16:17
5

The problem of using save_screenshot is that we cannot save an image in its original quality and cannot restore the alpha channel in an image. Therefore, I propose another solution. Here is a complete example using the selenium-wire library suggested by @codam_hsmits. It is possible to download images via ChromeDriver.

I have defined the following function to parse each request and save the request body to a file when necessary.

from seleniumwire import webdriver  # Import from seleniumwire
from urllib.parse import urlparse
import os
from mimetypes import guess_extension
import time
import datetime

def download_assets(requests,
                   asset_dir="temp",
                   default_fname="unnamed",
                   skip_domains=["facebook", "google", "yahoo", "agkn", "2mdn"],
                   exts=[".png", ".jpeg", ".jpg", ".svg", ".gif", ".pdf", ".bmp", ".webp", ".ico"],
                   append_ext=False):
    asset_list = {}
    for req_idx, request in enumerate(requests):
        # request.headers
        # request.response.body is the raw response body in bytes
        if request is None or request.response is None or request.response.headers is None or 'Content-Type' not in request.response.headers:
            continue
            
        ext = guess_extension(request.response.headers['Content-Type'].split(';')[0].strip())
        if ext is None or ext == "" or ext not in exts:
            #Don't know the file extention, or not in the whitelist
            continue
        parsed_url = urlparse(request.url)
        
        skip = False
        for d in skip_domains:
            if d in parsed_url.netloc:
                skip = True
                break
        if skip:
            continue
        
        frelpath = parsed_url.path.strip()
        if frelpath == "":
            timestamp = str(datetime.datetime.now().replace(microsecond=0).isoformat())
            frelpath = f"{default_fname}_{req_idx}_{timestamp}{ext}"
        elif frelpath.endswith("\\") or frelpath.endswith("/"):
            timestamp = str(datetime.datetime.now().replace(microsecond=0).isoformat())
            frelpath = frelpath + f"{default_fname}_{req_idx}_{timestamp}{ext}"
        elif append_ext and not frelpath.endswith(ext):
            frelpath = frelpath + f"_{default_fname}{ext}" #Missing file extension but may not be a problem
        if frelpath.startswith("\\") or frelpath.startswith("/"):
            frelpath = frelpath[1:]
        
        fpath = os.path.join(asset_dir, parsed_url.netloc, frelpath)
        if os.path.isfile(fpath):
            continue
        os.makedirs(os.path.dirname(fpath), exist_ok=True)
        print(f"Downloading {request.url} to {fpath}")
        asset_list[fpath] = request.url
        try:
            with open(fpath, "wb") as file:
                file.write(request.response.body)
        except:
            print(f"Cannot download {request.url} to {fpath}")
    return asset_list

Let's download some images from Google homepage to temp folder.

# Create a new instance of the Chrome/Firefox driver
driver = webdriver.Chrome()

# Go to the Google home page
driver.get('https://www.google.com')

# Download content to temp folder
asset_dir = "temp"

while True:
    # Please browser the internet, it will collect the images for every second
    time.sleep(1)
    download_assets(driver.requests, asset_dir=asset_dir)

driver.close()

Note that it cannot decide which images can be seen on the page rather than being hidden in the background, so the users should actively click the buttons or links to trigger new download requests.

Paco Wong
  • 610
  • 5
  • 11
3

So, just to stay relevant, here is a 2020 solution using seleniumwire, which is a package that gives you access to the requests made in a browser. You can use it easily as follows:

from seleniumwire import webdriver

# Sometimes, selenium randomly crashed when using seleniumwire, these options fixed that.
# Probably has to do with how it proxies everything.
options.add_argument('--ignore-certificate-errors')
options.add_argument('--ignore-ssl-errors')

driver = webdriver.Chrome(chrome_options=options)
driver.get("https://google.com")

for request in driver.requests:
    # request.path
    # request.method
    # request.headers
    # request.response is the response instance
    # request.response.body is the raw response body in bytes

    # if you are using it for a ton of requests, make sure to clear them:
    del driver.requests

Now, why would you need this? Well, for example for ReCaptcha bypassing, or for bypassing something like Incapsula. Use this at your own risk.

Harm Smits
  • 347
  • 1
  • 7
0

Here it is.

  • open the image with Selenium WebDriver
  • extract the width and the height of the image with BeautifulSoup
  • set the right current window size with driver.set_window_size, and take a screenshot with driver.save_screenshot
from bs4 import BeautifulSoup
from selenium import webdriver
 
import os
from urllib.parse import urlparse
 
url = 'https://image.rakuten.co.jp/azu-kobe/cabinet/hair1/hb-30-pp1.jpg'
 
filename = os.path.basename(urlparse(url).path)
filename_png = os.path.splitext(filename)[0] + '.png'  # change file extension to .png
 
opts = webdriver.ChromeOptions()
opts.headless = True
driver = webdriver.Chrome(options=opts)
 
driver.get(url)
 
# Get the width and height of the image
soup = BeautifulSoup(driver.page_source, 'lxml')
width = soup.find('img')['width']
height = soup.find('img')['height']
 
driver.set_window_size(width, height) # driver.set_window_size(int(width), int(height))
driver.save_screenshot(filename_png)

It also works for Google's image format, WebP.

Refer to Downlolad Google’s WebP Images via Take Screenshots with Selenium WebDriver.

SparkAndShine
  • 15,667
  • 17
  • 84
  • 129