Я пытаюсь отфильтровать данные с помощью Pandas, используя список значений, представляющих собой пару str book_tittle
и int book_price
:
import pandas as pd
import requests
from bs4 import BeautifulSoup
# settings_#############################################################################
isbn = {'9782756002484', '9782756025117', '9782756072449'}
url = 'https://www.abebooks.fr/servlet/SearchResults?sts=t&cm_sp=SearchF-_-NullResults-_-Results&isbn={}'
book_title = ["Mondes", "X-Wing"]
book_price = [100, 10]
#######################################################################################
### creation de lien à partir des codes ISBN#
def url_isbn(isbn):
merged = []
for link in isbn:
link_isbn = url.format(link)
merged.append(link_isbn)
return merged
### scraping each url from url_isbn
def get_data():
data = []
for i in url_isbn(isbn):
r = requests.get(i)
soup = BeautifulSoup(r.text, 'html.parser')
item = soup.find_all('div', {'class': 'result-data col-xs-9 cf'})
for x in item:
title = x.find('h2', {'class': 'title'}).text.replace('\n', '')
price = x.find('p', {'class': 'item-price'}).text.replace('EUR ', '').replace(',', '.')
url = 'https://www.abebooks.fr'+x.find('a', {'itemprop': 'url'})['href']
products = title, int(float(price)), url
data.append(products)
return data
###creating the dataframe
df = pd.DataFrame(get_data(), columns=["Titre", "Prix", "URL"])
###Filter data into the dataframe
for filtered in df:
df_final_to_email = filtered[(df['Titre'].str.contains(book_title) & (df.Prix < book_price))]
print(df_final_to_email)
Я получаю сообщение об ошибке: TypeError : unhashable type : 'list'
Я предполагаю, что не могу использовать список для фильтрации из-за сочетания типов данных, я тестировал Tuple и dict, я получаю ту же ошибку
Я также пытаюсь использовать df.query
, но он дает пустой фрейм данных
Фильтр позволит мне отфильтровать все книги, в названии которых есть «Mondes» по цене < 100, а также все книги, содержащие «X-Wing» по цене ниже < 10, я также добавлю больше товаров в найти с соответствующей ценой.
Титр | Приз |
---|---|
Адские миры | 95,10 |
Звездные войны, Mondes Infernaux | 75,50 |
Разбойник X-Wing | 9,50 |
Разбойная эскадрилья X-Wing | 7,50 |
Ничего про фильтрацию, но знаете, как я понял следующее :products = title, int(float(price)), url
? Мне пришлось использовать float
, так как я не могу преобразовать int(price)
как int, меня немного раздражает округление чисел в фрейме данных. (если какой-либо модератор может сказать мне, должен ли я сделать еще один пост для этой конкретной потребности? спасибо)
Спасибо за вашу помощь
Если вам нужны все совпадающие строки в фрейме данных, нет необходимости использовать цикл for
.
Может быть, попробуйте что-то вроде этого:
def find_book(str, price):
return df[ (df['Titre'].str.contains(str)) & (df['Prix']<price) ]
# find all books containing the substring 'Wing' in the title with price <7
find_book('Wing', 7)
Ошибка находится в вашем коде фильтрации:
df_final_to_email = filtered[(df['Titre'].str.contains(book_title) & (df.Prix < book_price))]
book_title
— это список. .str.contains
не работает со списком. Он работает с одной строкой или шаблоном регулярного выражения.
Если вы хотите найти книги со словом "Mondes" в названии и ценой менее 100 или "X-Wing" в названии и ценой менее 10, вы можете использовать следующий код фильтрации:
###Filter data into the dataframe
cond = pd.Series([False] * len(df), index=df.index)
for title, price in zip(book_title, book_price):
cond |= df["Titre"].str.contains(title) & df["Prix"].lt(price)
print(df[cond])
Как это устроено:
cond = <all False>
title
и price
оцените каждую строку, чтобы увидеть, соответствуют ли они критериям. Строка должна соответствовать только одному условию (title, price)
из списка, поэтому мы используем оператор «на месте or
» (|=
) для обновления нашего списка выбора.Оператор |=
эквивалентен:
cond = cond | (df["Titre"].str.contains(title) & df["Prix"].lt(price))
ву, отлично, я бы никогда его не нашел, не могли бы вы объяснить мне код, пожалуйста :)?
Я считаю, что этот фрагмент кода фильтрует фрейм данных, как вы хотите (не проверено):
df_final_to_email = pd.concat([df.loc[df["Titre"].str.contains(t) & df["Prix"].lt(p)]
for t,p in zip(book_title, book_price)])
Спасибо, но мне нужно соответствовать списку в
book_title
иbook_price
:), я сделалfind_book(book_title, book_price
, но получаю ошибкуTypeError : unhashable type : 'list'