Ich möchte eine Liste von URLs (in einer Spalte eines Datenrahmens df) auf ihre Statuscodes überprüfen (404, 403 und 200 scheinen die interessanten zu sein). Ich habe eine Funktion definiert, die den Job erledigt. Es wird jedoch eine for-Schleife verwendet, die ineffizient ist (ich habe eine lange Liste von URLs!).

Hat jemand einen Hinweis, wie man es effizienter macht? Optimalerweise würde der zurückgegebene Statuscode auch in einer neuen Spalte des Datenrahmens angezeigt, z. df ['status_code_url'].

def url_access(df, column):
    e_404 =0
    e_403 =0
    e_200 =0
    for i in range(0, len(df)):
        if requests.head(df[column][i]).status_code == 404:
            e_404= e_404+1
        elif requests.head(df[column][i]).status_code == 403:
            e_403 = e_403 +1
        elif requests.head(df[column][i]).status_code == 200:
            e_200 = e_200 +1
        else:
            print(requests.head(df[column][i]).status_code)

    return ("Statistics about " + column , '{:.1%}'.format(e_404/len(df)) 
            + " of links to intagram post return 404", '{:.1%}'.format(e_403/len(df)) 
            + " of links to intagram post return 403", '{:.1%}'.format(e_200/len(df)) 
            + " of links to intagram post return 200")

Vielen Dank!

1
Nini 18 Apr. 2018 im 14:49

3 Antworten

Beste Antwort

pandas.DataFrame.apply (oder besser gesagt die normale requests Bibliothek) kann jeweils nur eine Anfrage stellen. Um mehrere Anfragen gleichzeitig zu bearbeiten, können Sie requests_futures verwenden (installieren Sie es mit { {X3}}):

import pandas as pd
from requests_futures.sessions import FuturesSession

def get_request(url):
    session = FuturesSession()
    return session.head(url)


def get_status_code(r):
    return r.result().status_code

if __name__ == "__main__":
    urls = ['http://python-requests.org',
            'http://httpbin.org',
            'http://python-guide.org',
            'http://kennethreitz.com']
    df = pd.DataFrame({"url": urls})
    df["status_code"] = df["url"].apply(get_request).apply(get_status_code)

Anschließend können Sie beispielsweise groupby verwenden, wie von @Aritesh in ihre Antwort:

stats = df.groupby('status_code')['url'].count().reset_index()
print(stats)
#    status_code  url
  0          200    1
  1          301    3

Damit möchten Sie wahrscheinlich auch einen gewissen Schutz vor Verbindungsfehlern und eine Zeitüberschreitung hinzufügen:

import numpy as np
import requests

def get_request(url):
    session = FuturesSession()
    return session.head(url, timeout=1)

def get_status_code(r):
    try:
        return r.result().status_code
    except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout):
        return 408 # Request Timeout

ips = np.random.randint(0, 256, (1000, 4))
df = pd.DataFrame({"url": ["http://" + ".".join(map(str, ip)) for ip in ips]})
df["status_code"] = df["url"].apply(get_request).apply(get_status_code)
df.groupby('status_code')['url'].count().reset_index()
#    status_code  url
# 0          200    3
# 1          302    2
# 2          400    2
# 3          401    1
# 4          403    1
# 5          404    1
# 6          408  990
0
Graipher 18 Apr. 2018 im 13:09

Verwenden Sie Pandas, apply und groupby -

def url_access(x):
    return requests.head(x).status_code


df['Status'] = df['url'].apply(url_access)

dfcount = df.groupby('Status')['url'].count().reset_index()
3
Aritesh 18 Apr. 2018 im 12:10

Grundsätzlich scheint Ihre Aufgabe zu sein:

  1. URL-Statuscode abrufen
  2. Sammeln Sie Antworten für alle
  3. Prozentsätze berechnen

Für den ersten Schritt verwenden Sie:

def get_code(url):
    return requests.head(url).status_code

Für den zweiten Schritt wenden Sie diese Funktion auf die Datenrahmenspalte an (siehe) https://pandas.pydata.org/pandas- docs / stabil / generiert / pandas.DataFrame.apply.html

resp_df = df[column].apply(get_code, axis=1) 

Für den dritten Schritt können Sie Operationen über der Spalte verwenden, um Prozentsätze zu berechnen:

resp_df[resp_df == 404].sum() / len (resp_df) 

(Notizcode nicht ausgeführt)

0
Evgeny 18 Apr. 2018 im 12:17