У меня есть следующий код для получения IP-информации:
import requests
import json
import pandas as pd
import swifter
def get_ip(ip):
response = requests.get ("http://ip-api.com/json/" + ip.rstrip())
geo = response.json()
location = {'lat': geo.get('lat', ''),
'lon': geo.get('lon', ''),
'region': geo.get('regionName', ''),
'city': geo.get('city', ''),
'org': geo.get('org', ''),
'country': geo.get('countryCode', ''),
'query': geo.get('query', '')
}
return(location)
Чтобы применить его ко всему массиву данных IP (df), я использую следующее:
df=pd.DataFrame(['85.56.19.4','188.85.165.103','81.61.223.131'])
for lab,row in df.iterrows():
dip = get_ip(df.iloc[lab][0])
try:
ip.append(dip["query"])
private.append('no')
country.append(dip["country"])
city.append(dip["city"])
region.append(dip["region"])
organization.append(dip["org"])
latitude.append(dip["lat"])
longitude.append(dip["lon"])
except:
ip.append(df.iloc[lab][0])
private.append("yes")
Однако, поскольку iterrows очень медленный, и мне нужно больше производительности, я хочу использовать swiftapply, что является расширением функции apply. Я использовал это:
def ip(x):
dip = get_ip(x)
if (dip['ip']=='private')==True:
ip.append(x)
private.append("yes")
else:
ip.append(dip["ip"])
private.append('no')
country.append(dip["country"])
city.append(dip["city"])
region.append(dip["region"])
organization.append(dip["org"])
latitude.append(dip["lat"])
longitude.append(dip["lon"])
df.swifter.apply(ip)
И я получаю следующую ошибку: AttributeError: ("Объект" Серии "не имеет атрибута" rstrip "," произошел с индексом 0 ")
Как я могу это исправить?
rstrip
- операция строки. Чтобы применить операцию строки к серии Series
вы должны сначала вызвать функцию str
в серии, которая позволяет выполнять операции векторизованных строк в Series
.
В частности, в вашем коде изменения ip.rstrip()
на ip.str.rstrip()
должны разрешить ваш AttributeError
.
После того, как копаться немного выясняется requests.get
операции, которую вы пытаетесь выполнить не может быть векторизации в pandas
(см Использование Python запросов для нескольких URLS в dataframe). Я взломал следующее, которое должно быть немного более эффективным, чем использование iterrows
. Что делает следующее: np.vectorize
используется для запуска функции для получения информации для каждого IP-адреса. Вход в местоположение сохраняется как новые столбцы в новом DataFrame.
Во-первых, я изменил вашу функцию get_ip
чтобы вернуть словарь location
, а не (location)
.
Затем я создал функцию векторизации, используя np.vectorize
:
vec_func = np.vectorize(lambda url: get_ip(url))
Наконец, vec_func
применяется к df
для создания нового DataFrame, который объединяет df
с выводом местоположения из vec_func
где df[0]
- столбец с вашими URL-адресами:
new_df = pd.concat([df, pd.DataFrame(vec_func(df[0]), columns=["response"])["response"].apply(pd.Series)], axis=1)
Приведенный выше код возвращает ответ API в виде словаря для каждой строки в вашем DataFrame, а затем сопоставляет словарь с столбцами в DataFrame. В итоге ваш новый DataFrame будет выглядеть так:
0 lat lon region city org country query
0 85.56.19.4 37.3824 -5.9761 Andalusia Seville Orange Espana ES 85.56.19.4
1 188.85.165.103 41.6561 -0.8773 Aragon Zaragoza Vodafone Spain ES 188.85.165.103
2 81.61.223.131 40.3272 -3.7635 Madrid Leganés Vodafone Ono ES 81.61.223.131
Надеемся, что это устраняет ошибку InvalidSchema
и дает вам немного лучшую производительность, чем iterrows()
.
rstrip()
- это функция, которая работает только со строками. Кажется, вы используете его сip.rstrip()
объектом, но я не уверен, где (ip.rstrip()
- единственное вхождениеrstrip()
, аip
, скорее всего, строка)