Как найти указанный c текст в коде HTML веб-сайта с Python и BeautifulSoup? - PullRequest
0 голосов
/ 20 апреля 2020

Совершенно новый для HTML и Python здесь. Я пытаюсь очистить сайт с помощью Python, чтобы найти данные аукциона. Я хочу найти все объявления с текстом «lb, lbs., Pound» и так далее. Вот пример списка HTML кода, который меня интересует:

    <a class="product" href="/Item/91150404">
    <div class="title">
                30.00 LB Lego Mini Figures Lego People Grab Bag
                                        <br>Bids: 7                                    </div> </a>

Я разобрался, как получить ResultSet всех тегов "title" с переменной title_all, но мне хотелось бы для дальнейшей фильтрации всех аукционных списков, чтобы показывать только те, у которых в имени указано "LB". Я прочитал документацию BeautifulSoup, и лучшее, что я смог сделать, это вернуть пустой список []. Вот мой Python код:

import requests
import re
from bs4 import BeautifulSoup

url = 'https://www.shopgoodwill.com/Listings?st=&sg=&c=388&s=&lp=0&hp=999999&sbn=false&spo=false&snpo=false&socs=false&sd=false&sca=false&caed=4/18/2020&cadb=7&scs=false&sis=false&col=0&p=1&ps=40&desc=false&ss=0&UseBuyerPrefs=true'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')

title_all=soup.findAll(True,class_=['title'])
result=soup.findAll('div', text = re.compile('LB'),attrs = {'class' : 'title'})
print(result)
#does not work

Я также пытался прочитать подобные вопросы здесь и реализовать ответы, но я застрял. Любая помощь будет принята с благодарностью! Я использую Python 3.7.3 и BeautifulSoup 4. Спасибо!

Ответы [ 3 ]

1 голос
/ 20 апреля 2020

Вместо:

text=re.compile('LB')

Попробуйте:

string=re.compile('LB')

Документация

0 голосов
/ 20 апреля 2020

Другое решение.

from simplified_scrapy import SimplifiedDoc,req,utils
# url = 'https://www.shopgoodwill.com/Listings?st=&sg=&c=388&s=&lp=0&hp=999999&sbn=false&spo=false&snpo=false&socs=false&sd=false&sca=false&caed=4/18/2020&cadb=7&scs=false&sis=false&col=0&p=1&ps=40&desc=false&ss=0&UseBuyerPrefs=true'
# html = req.get(url)
# url = 'https://www.shopgoodwill.com/Listings?st=&sg=&c=388&s=&lp=0&hp=999999&sbn=false&spo=false&snpo=false&socs=false&sd=false&sca=false&caed=4/18/2020&cadb=7&scs=false&sis=false&col=0&p=1&ps=40&desc=false&ss=0&UseBuyerPrefs=true'
# html = requests.get(url).text
html = '''
<a class="product" href="/Item/91150404">
    <div class="title">
                30.00 LB Lego Mini Figures Lego People Grab Bag
                                        <br>Bids: 7
    </div>
</a>
'''
doc = SimplifiedDoc(html)
title_all = doc.getElementsByReg('( LB | LBS )',tag="div").text
print(title_all)

Результат:

['30.00 LB Lego Mini Figures Lego People Grab Bag Bids: 7']

Вот еще несколько примеров. https://github.com/yiyedata/simplified-scrapy-demo/tree/master/doc_examples

0 голосов
/ 20 апреля 2020
from bs4 import BeautifulSoup
import datetime as dt
import requests

url = 'https://www.shopgoodwill.com/Listings?st=&sg=&c=388&s=&lp=0&hp=999999&sbn=false&spo=false&snpo=false&socs=false&sd=false&sca=false&caed=4/18/2020&cadb=7&scs=false&sis=false&col=0&p=1&ps=40&desc=false&ss=0&UseBuyerPrefs=true'
r = requests.get(url)
bs = BeautifulSoup(r.text, "html.parser")

# Gathering products.
bs_products = bs.findAll("a", {"class": "product"})

# Gathering listing information for each product.
products = [] 
for product in bs_products:
    price_str = product.find("div", {"class": "price"}).text.strip()
    price_int = int(''.join(filter(lambda i: i.isdigit(), price_str)))

    product = {"img": product.find("img", {"class": "lazy-load"}).get("data-src"), 
               "num": int(product.find("div", {"class": "product-number"}).text.split(":")[1]), 
               "title": product.find("div", {"class": "title"}).next_element.strip(),
               "time_left": dt.datetime.strptime(product.find("div", {"class": "timer"}).get("data-countdown"), "%m/%d/%Y %I:%M:%S %p"),
               "price": price_int}

    products.append(product)

filter_LB = list(filter(lambda product: "LB" in product['title'], products))
print(filter_LB)

Выходы:

[{'img': 'https://sgwproductimages.azureedge.net/109/4-16-2020/56981071672752ssdt-thumb.jpg',
  'num': 91150404,
  'title': '30.00 LB Lego Mini Figures Lego People Grab Bag',
  'time_left': datetime.datetime(2020, 4, 21, 19, 20),
  'price': 444500},
 {'img': 'https://sgwproductimages.azureedge.net/5/4-14-2020/814151314749m.er-thumb.jpg',
  'num': 91000111,
  'title': '20 LBS of Bulk Loose Lego Pieces',
  'time_left': datetime.datetime(2020, 4, 19, 18, 6),
  'price': 4600}]

Что я бы порекомендовал сделать, так это использовать BS4 для того, для чего он предназначен - утилизацию - и затем использовать Python для фильтрации ваших объектов. Я не буду возражать против утверждения, что BS4 может фильтровать, но я всегда обнаруживал, что лучше сначала реализовать общее решение, а затем разобраться со спецификой в ​​необходимых случаях.

Если вы не знакомы с filter, ознакомьтесь с документацией здесь . Если вы не знаете, что такое lambda, это функция, записанная в одну строку. Все filter проходит через ваши объекты oop и применяет данную функцию lambda. Какой бы объект не вернул True внутри lambda, filter вернет его.

def func(a):
    return a + 2

func(4) # >>> 6

func = lambda a: a + 2

func(4) # >>> 6

Счастливого программирования! :)


Ссылки:


Редактировать: для обсуждения ниже. Скажем, мы хотим отфильтровать числа, чтобы они всегда были выше или равны 5. Мы можем сделать это несколькими способами:

l = [1, 2, 3, 4, 5, 6, 7]

# Traditional filtering way. Makes sense.
filtered_l = []
for i in l:
    if i >= 5:
        filtered_l.append(i)

# Lambda + Filter way
filtered_l = list(filter(lambda i: i >= 5, l))

# Function + Filter Way
def filtering(i): # Notice this function returns either True or False. 
    return i >= 5
filtered_l = list(filter(filtering, l))

Вы можете спросить, почему мы делаем list(filter()) вместо простого filter() , Это потому, что filter возвращает iterable, который изначально не был списком. Это объект, через который вы можете взаимодействовать . Поэтому мы извлекаем ресурсы filter, преобразовывая их в список. Точно так же вы можете преобразовать list в итерируемое (что дает вам дополнительную функциональность и контроль):

l = [1, 2, 3, 4, 5]
iter_l = iter(l) # >>> <list_iterator object at 0x10aa9ee50>

next(iter_l) # >>> 1
next(iter_l) # >>> 2
next(iter_l) # >>> 3
next(iter_l) # >>> 4
next(iter_l) # >>> 5

next(iter_l)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

Вы можете спросить "зачем использовать iter вместо простого использования списка? " Ответ в том, что вы можете перегрузить функциональность __iter__ и __next__ в классах, чтобы превратить их в итерируемые классы (классы, в которых вы можете вызывать циклы for):

import random

class RandomIterable:
    def __iter__(self):
        return self

    def __next__(self):
        if random.choice(["go", "go", "stop"]) == "stop":
            raise StopIteration  # signals "the end"
        return 1

, что позволяет нам выполнять итерации сам класс:

for eggs in RandomIterable():
    print(eggs)

Или, как вы использовали в filter, просто получите список:

list(RandomIterable())
>>> [1]

, который в этом случае вернет вам количество времени ( отмеченные 1), что слово stop было выбрано случайным образом. Если возвращение было [1, 1], то stop было выбрано дважды подряд. Конечно, это глупый пример, но, надеюсь, теперь вы видите, как list, filter и lambda работают вместе для фильтрации списков (или итерируемых) в Python.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...