2013-08-26 14 views
27

का उपयोग कर फ़ाइल डाउनलोड करना मैं अजगर और सेलेनियम पर काम कर रहा हूं। मैं सेलेनियम का उपयोग कर घटना पर क्लिक करने से फ़ाइल डाउनलोड करना चाहता हूं। मैंने निम्नलिखित कोड लिखा था।सेलेनियम

from selenium import webdriver 
from selenium.common.exceptions import NoSuchElementException 
from selenium.webdriver.common.keys import Keys 

browser = webdriver.Firefox() 
browser.get("http://www.drugcite.com/?q=ACTIMMUNE") 

browser.close() 

मैं यूआरएल से "निर्यात डेटा" नाम के साथ लिंक से दोनों फाइलें डाउनलोड करना चाहता हूं। मैं इसे कैसे प्राप्त कर सकता हूं क्योंकि यह केवल क्लिक ईवेंट के साथ काम करता है।

धन्यवाद

+1

मैं 'urllib' का उपयोग करके पुनः प्राप्त करता हूं और डाउनलोड करने के लिए' urllib.urlretrieve (url) 'का उपयोग करता हूं जहां' url' यूआरएल है जो लिंक भेजता है आप – Serial

+0

नहीं क्योंकि यह केवल क्लिक ईवेंट के साथ काम करता है। – sam

+0

लेकिन यदि आप पृष्ठ के HTML पार्स आप क्लिक करें घटना ब्राउज़र को भेजता है लिंक मिलता है और का उपयोग करें कि – Serial

उत्तर

41

find_element(s)_by_* का उपयोग कर लिंक हैं, फिर click विधि कॉल।

from selenium import webdriver 

# To prevent download dialog 
profile = webdriver.FirefoxProfile() 
profile.set_preference('browser.download.folderList', 2) # custom location 
profile.set_preference('browser.download.manager.showWhenStarting', False) 
profile.set_preference('browser.download.dir', '/tmp') 
profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'text/csv') 

browser = webdriver.Firefox(profile) 
browser.get("http://www.drugcite.com/?q=ACTIMMUNE") 

browser.find_element_by_id('exportpt').click() 
browser.find_element_by_id('exporthlgt').click() 

डाउनलोड संवाद को रोकने के लिए प्रोफ़ाइल मैनिपुलेशन कोड जोड़ा गया।

+0

क्या किया जाना चाहिए यदि मैं ब्राउजर को छिपाना चाहता हूं या ब्राउज़र को प्रसंस्करण करते समय छुपा/न्यूनतम मोड में रखना चाहता हूं? – sam

+0

@ एसएएम, 'हेडलेस' + 'सेलेनियम' + 'फ़ायरफ़ॉक्स' के लिए खोजें। – falsetru

+0

@ एसएएम, या 'फैन्रोमज', 'भूतस्ट्रिवर'। – falsetru

4

मैं यह समाधान स्वीकार करूंगा कि यह समाधान फ़ायरफ़ॉक्स प्रोफाइल सेव करने के लिए थोड़ा और हैकी है, लेकिन यह क्रोम और फ़ायरफ़ॉक्स दोनों में काम करता है, और ब्राउज़र-विशिष्ट सुविधा पर निर्भर नहीं है जो किसी भी समय बदल सकता है । और यदि कुछ और नहीं है, तो शायद यह किसी को भविष्य की चुनौतियों को हल करने के तरीके पर थोड़ा अलग परिप्रेक्ष्य देगा।

किसी और चीज की: सुनिश्चित करें कि आप सेलेनियम है और स्थापित pyvirtualdisplay ...

  • अजगर 2: sudo pip install selenium pyvirtualdisplay
  • अजगर 3: sudo pip3 install selenium pyvirtualdisplay

जादू

import pyvirtualdisplay 
import selenium 
import selenium.webdriver 
import time 
import base64 
import json 

root_url = 'https://www.google.com' 
download_url = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png' 

print('Opening virtual display') 
display = pyvirtualdisplay.Display(visible=0, size=(1280, 1024,)) 
display.start() 
print('\tDone') 

print('Opening web browser') 
driver = selenium.webdriver.Firefox() 
#driver = selenium.webdriver.Chrome() # Alternately, give Chrome a try 
print('\tDone') 

print('Retrieving initial web page') 
driver.get(root_url) 
print('\tDone') 

print('Injecting retrieval code into web page') 
driver.execute_script(""" 
    window.file_contents = null; 
    var xhr = new XMLHttpRequest(); 
    xhr.responseType = 'blob'; 
    xhr.onload = function() { 
     var reader = new FileReader(); 
     reader.onloadend = function() { 
      window.file_contents = reader.result; 
     }; 
     reader.readAsDataURL(xhr.response); 
    }; 
    xhr.open('GET', %(download_url)s); 
    xhr.send(); 
""".replace('\r\n', ' ').replace('\r', ' ').replace('\n', ' ') % { 
    'download_url': json.dumps(download_url), 
}) 

print('Looping until file is retrieved') 
downloaded_file = None 
while downloaded_file is None: 
    # Returns the file retrieved base64 encoded (perfect for downloading binary) 
    downloaded_file = driver.execute_script('return (window.file_contents !== null ? window.file_contents.split(\',\')[1] : null);') 
    print(downloaded_file) 
    if not downloaded_file: 
     print('\tNot downloaded, waiting...') 
     time.sleep(0.5) 
print('\tDone') 

print('Writing file to disk') 
fp = open('google-logo.png', 'wb') 
fp.write(base64.b64decode(downloaded_file)) 
fp.close() 
print('\tDone') 
driver.close() # close web browser, or it'll persist after python exits. 
display.popen.kill() # close virtual display, or it'll persist after python exits. 

Explaination

हम पहले डोमेन हम से एक फ़ाइल डाउनलोड लक्षित कर रहे हैं पर एक URL को लोड। यह हमें cross site scripting समस्याओं में भाग दिए बिना, उस डोमेन पर AJAX अनुरोध करने की अनुमति देता है।

अगला, हम डीओएम में कुछ जावास्क्रिप्ट इंजेक्शन कर रहे हैं जो AJAX अनुरोध को बंद कर देता है। एक बार AJAX अनुरोध एक प्रतिक्रिया देता है, हम प्रतिक्रिया लेते हैं और इसे एक फ़ाइल रीडर ऑब्जेक्ट में लोड करते हैं। वहां से हम readAsDataUrl() को कॉल करके फ़ाइल की बेस 64 एन्कोडेड सामग्री निकाल सकते हैं। इसके बाद हम बेस 64 एन्कोडेड सामग्री ले रहे हैं और इसे window पर जोड़ रहे हैं, जो एक वैश्विक रूप से सुलभ चर है।

अंत में, क्योंकि AJAX अनुरोध असीमित है, हम पाइथन में प्रवेश करते हैं जबकि लूप सामग्री को विंडो में जोड़ने के लिए प्रतीक्षा करते हैं। एक बार इसे जोड़ने के बाद, हम विंडो से पुनर्प्राप्त बेस 64 सामग्री को डीकोड करते हैं और इसे फ़ाइल में सहेजते हैं।

यह समाधान सेलेनियम द्वारा समर्थित सभी आधुनिक ब्राउज़रों में काम करना चाहिए, और यह पाठ या बाइनरी, और सभी माइम प्रकारों में काम करता है या नहीं।

वैकल्पिक दृष्टिकोण

जब मैं इस परीक्षण नहीं किया, सेलेनियम आप जब तक एक तत्व डोम में मौजूद है इंतजार करने की क्षमता को वहन करता है। वैश्विक रूप से सुलभ चर तक पॉपअप होने तक लूपिंग करने के बजाय, आप डीओएम में किसी विशेष आईडी के साथ एक तत्व बना सकते हैं और डाउनलोड की गई फ़ाइल को पुनर्प्राप्त करने के लिए ट्रिगर के रूप में उस तत्व के बाध्यकारी का उपयोग कर सकते हैं।

1

क्रोम में मैं क्या लिंक पर क्लिक करके फ़ाइलों को डाउनलोड कर रहा है, तो मैं chrome://downloads पृष्ठ को खोलने और फिर छाया डोम से डाउनलोड की गई फ़ाइलों की सूची इस तरह पुनः प्राप्त:

docs = document 
    .querySelector('downloads-manager') 
    .shadowRoot.querySelector('#downloads-list') 
    .getElementsByTagName('downloads-item') 

यह समाधान क्रोम के लिए रोक लगा दी है , डेटा में फ़ाइल पथ और डाउनलोड तिथि जैसी जानकारी भी होती है। (नोट करें कि यह कोड जेएस से है, सही पायथन वाक्यविन्यास नहीं हो सकता है)