2017-08-12 2 views
3

Für Forschungszwecke muss ich eine Reihe von gutartigen Programmen erstellen. Zuerst muss ich diese Programme von http://downloads.informer.com bekommen. Um dies zu tun, habe ich ein Python-Skript geschrieben, das jede Download-Seite iteriert und die Download-Links in eine Liste extrahiert. Danach verwendet das Skript diese Links zum Herunterladen der Programme (diese Programme sind exe, msi oder zip-Dateien). Leider läuft das Skript in diesem Schritt in Fehler, der besagt, dass (AttributeError: 'Request' -Objekt kein Attribut 'decode' hat).Crawlen und Herunterladen von Dateien von informer.com mit Python-Skript

Es folgt das Skript, das funktioniert auf einer einzigen Seite und retrevies einzigen Programm (der Einfachheit halber):

Der Fehler ich folgt

import wget 
from urllib.request import urlopen as uReq 
from bs4 import BeautifulSoup as soup 
my_url = 'http://sweet-home-3d.informer.com/download' 

import urllib.request 
req = urllib.request.Request(
    my_url, 
    data=None, 
    headers={ 
     'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36' 
    } 
) 


uClient = uReq(req) 
page_html = uClient.read() 

page_soup = soup(page_html, 'lxml') 

cont01 = page_soup.findAll('a', {'class':'download_button'}) 

conts = cont01[1] 
ref= conts['href'] 

addr = urllib.request.Request(
    ref, 
    data=None, 
    headers={ 
     'User-Agent': 'Mozilla/5.0' 
    } 
) 
wget.download(addr) 
:

AttributeError       Traceback (most recent call last) 
<ipython-input-1-93c4caaa1777> in <module>() 
    31  } 
    32) 
---> 33 wget.download(addr) 

C:\Users\bander\Anaconda3\lib\site-packages\wget.py in download(url, out, bar) 
    503 
    504  # get filename for temp file in current directory 
--> 505  prefix = detect_filename(url, out) 
    506  (fd, tmpfile) = tempfile.mkstemp(".tmp", prefix=prefix, dir=".") 
    507  os.close(fd) 

C:\Users\bander\Anaconda3\lib\site-packages\wget.py in detect_filename(url, out, headers, default) 
    482   names["out"] = out or '' 
    483  if url: 
--> 484   names["url"] = filename_from_url(url) or '' 
    485  if headers: 
    486   names["headers"] = filename_from_headers(headers) or '' 

C:\Users\bander\Anaconda3\lib\site-packages\wget.py in filename_from_url(url) 
    228  """:return: detected filename as unicode or None""" 
    229  # [ ] test urlparse behavior with unicode url 
--> 230  fname = os.path.basename(urlparse.urlparse(url).path) 
    231  if len(fname.strip(" \n\t.")) == 0: 
    232   return None 

C:\Users\bander\Anaconda3\lib\urllib\parse.py in urlparse(url, scheme, allow_fragments) 
    292  Note that we don't break the components up in smaller bits 
    293  (e.g. netloc is a single string) and we don't expand % escapes.""" 
--> 294  url, scheme, _coerce_result = _coerce_args(url, scheme) 
    295  splitresult = urlsplit(url, scheme, allow_fragments) 
    296  scheme, netloc, url, query, fragment = splitresult 

C:\Users\bander\Anaconda3\lib\urllib\parse.py in _coerce_args(*args) 
    112  if str_input: 
    113   return args + (_noop,) 
--> 114  return _decode_args(args) + (_encode_result,) 
    115 
    116 # Result objects are more helpful than simple tuples 

C:\Users\bander\Anaconda3\lib\urllib\parse.py in _decode_args(args, encoding, errors) 
    96 def _decode_args(args, encoding=_implicit_encoding, 
    97      errors=_implicit_errors): 
---> 98  return tuple(x.decode(encoding, errors) if x else '' for x in args) 
    99 
    100 def _coerce_args(*args): 

C:\Users\bander\Anaconda3\lib\urllib\parse.py in <genexpr>(.0) 
    96 def _decode_args(args, encoding=_implicit_encoding, 
    97      errors=_implicit_errors): 
---> 98  return tuple(x.decode(encoding, errors) if x else '' for x in args) 
    99 
    100 def _coerce_args(*args): 

AttributeError: 'Request' object has no attribute 'decode' 

ich gratefull wäre, wenn jemand könnte hilf mir, das zu beheben. Danke im Voraus.

+0

Ihr Problem ist wahrscheinlich, dass ‚addr‘ ist nicht die wirkliche Verbindung zu dem Datei, aber dass es umleitet. Klicken Sie auf den Link, auf dem Chrome Inspector ausgeführt wird (wählen Sie die Registerkarte "Netzwerk" aus) und sehen Sie, wo er den tatsächlichen Inhalt abruft. – jlaur

+0

Sie haben Recht, der eigentliche Link ist anders. zum Beispiel zeigt es folgenden Link im Inspektor: http://download.informer.com/win-1193020099-a188ca2c-5607e42f/flow_v111_full.zip Aber wenn ich es in Addr setzen, gibt es wieder denselben Fehler. Und wie man diesen tatsächlichen Link crawlt. – Bander

+0

Sie könnten versuchen, das endgültige Ziel zu verfolgen. Werfen Sie einen Blick auf diese: https://Stackoverflow.com/a/20475712/8240959 – jlaur

Antwort

1

Eigentlich brauchen Sie Selen dafür nicht. Es ist ein Cookie-Problem. Ich bin mir sicher, dass du auch mit Urllib Cookies machen kannst, aber das ist nicht mein Spezialgebiet.

Wenn Sie den Job zu erledigen sind - ohne einen Browser und wget - in Anfragen, können Sie die Dateien wie so greifen:

import requests 
from bs4 import BeautifulSoup as bs 

# you need headers or the site won't let you grab the data 
headers = { 

    "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3181.0 Safari/537.36" 
} 
url = 'http://sweet-home-3d.informer.com/download/' 

# you need a cookie to download. Create a persistens session 
s = requests.Session() 
r = s.get(url, headers=headers) 
soup = bs(r.text, "html.parser") 

# all download options lie in a div with class table 
links_table = soup.find('div', {'class': 'table'}) 
file_name = links_table.find('div', {'class': 'table-cell file_name'})['title'] 
download_link = links_table.find('a', {'class': 'download_button'})['href'] 

# for some reason the url-page doesn't set the cookie you need. 
# the subpages do, so we need to get it from one of them - before we call download_link 

cookie_link = links_table.a['href'] 
r = s.get(cookie_link, headers=headers) 

# now with a cookie set, we can download the file 
r = s.get(download_link,headers=headers) 
with open(file_name, 'wb') as f: 
    f.write(r.content) 
+0

Danke jlaur, es funktioniert gut mit Ihrem Code. – Bander

+0

Gern geschehen. Bitte schließen Sie die Frage, indem Sie die Antwort akzeptieren. Es offen zu lassen, verursacht viele andere hilfreiche Leute, Ihre Frage vergebens zu besuchen ... – jlaur

2

Wget gibt einen HTTP-Fehler 503: Dienst vorübergehend nicht verfügbar, wenn direkt mit der richtigen URL aufgerufen wird. Ich denke, es ist auf dem Server blockiert. Der Download-Link wird von JavaScript generiert. Sie können Selen verwenden. Dadurch wird JavaScript ausgeführt, um die URL zu erhalten. Ich habe Selenium mit PhantomJS ausprobiert und es hat nicht funktioniert. Aber mit Chrome hat es getan.

Erste Selen installieren:

sudo pip3 install selenium 

Dann einen Fahrer bekommen https://sites.google.com/a/chromium.org/chromedriver/downloads und steckte es in Ihnen Weg. Sie können eine kopflose Version von Chrome "Chrome Canary" verwenden, wenn Sie (anders als ich) auf Windows oder Mac sind.

from selenium import webdriver 
from time import sleep 

url = 'http://sweet-home-3d.informer.com/download' 
browser = webdriver.Chrome() 
browser.get(url) 
browser.find_element_by_class_name("download_btn").click() 
sleep(360) # give it plenty of time to download this will depend on you internet connection 
browser.quit() 

Die Datei wird in den Ordner Downloads heruntergeladen. Wenn es zu früh beendet wird, erhalten Sie einen Teil der Datei mit der zusätzlichen Dateierweiterung .crdownload. Wenn dies geschieht, erhöhen Sie den Wert, den Sie an den Ruhezustand übergeben haben.