Scrappeando propiedades con Python

Hace un tiempo estaba buscando departmentamento para alquilar y me frustraba entrar periodicamente a las páginas de propiedades sólo para encontrarme una y otra vez con los mismos inmuebles.

Buscar un Departmentamento es una tarea tediosa y estresante, por eso, se me ocurrió dar vuelta el problema y transformarlo en algo divertido: crear un bot que busque las propiedades y avise vía chat cuando aparece una nueva.

El código es relativamente sencillo , menos de 100 líneas de python, pero de todos modos vamos a seguirlo paso por paso para ver qué es lo que hace.

URL 및 메인



Primero notamos que tenemos un set con las URLs de búsqueda:


urls = {
    "https://www.argenprop.com/departamento-alquiler-barrio-chacarita-hasta-25000-pesos-orden-masnuevos",
    "https://www.zonaprop.com.ar/departamento-alquiler-villa-crespo-con-terraza-orden-publicado-descendente.html",
}

URL을 단순하게 만들면 새로운 스크립트로 사이트를 읽을 수 있습니다. En este caso departmentamentos en Chacarita hasta 25.000 pesos y en Villa Crespo con terraza(sin límite de precio). Ambas en distintos portales de búsqueda. "más nuevos"로 결정된 결과가 중요합니다.

La función principal( main )은 los pasos a seguir를 정의합니다.


for url in urls: # 1
  res = requests.get(url) # 2
  ads = list(extract_ads(url, res.text)) # 3
  seen, unseen = split_seen_and_unseen(ads) # 4

  print("{} seen, {} unseen".format(len(seen), len(unseen)))

  for u in unseen: # 5
    notify(u)

  mark_as_seen(unseen) # 6

  • Para cada una de nuestras URL definidas previamente
  • Ir a buscar los resultados
  • 추가 로스 광고 링크
  • Dividir 링크 en vistos y no vistos
  • Para los no vistos, notificar por mensaje
  • Marcar los no vistos como vistos

  • De acá nos enfocamos en las partes más interesantes:

    추가 링크 드 로스 광고



    Cada página tiene su estructura propia, para eso definimos la dataclass Parser :

    @dataclass
    class Parser:
        website: str
        link_regex: str
    
        def extract_links(self, contents: str):
            soup = BeautifulSoup(contents, "lxml")
            ads = soup.select(self.link_regex)
            for ad in ads:
                href = ad["href"]
                _id = sha1(href.encode("utf-8")).hexdigest()
                yield {"id": _id, "url": "{}{}".format(self.website, href)}
    
    
    parsers = [
        Parser(website="https://www.zonaprop.com.ar", link_regex="a.go-to-posting"),
        Parser(website="https://www.argenprop.com", link_regex="div.listing__items div.listing__item a"),
        Parser(website="https://inmuebles.mercadolibre.com.ar", link_regex="li.results-item .rowItem.item a"),
    ]
    

    Como vemos, cadaParser actúa sobre un dominio en specific de los que soportamos, porque cada página tiene su estructura de HTML propia.

    Con beautifulsoup podemos usar CSS query para movernos por el markup y obtener los link de los avisos que nos interesan.

    Una vez extraídos los devolvemos junto con un id que generamos hasheando la URL del aviso (esto será útil para marcar los ya vistos).

    녹음기 링크 방문



    El bot no sería muy útil si reportara todo el tiempo lo mismo, deberíamos buscar una forma de "recordar"qué avisos ya envíamos.

    Una forma sencilla es un archivo de texto seen.txt con los id s de los avisos reportados:

    def split_seen_and_unseen(ads):
        history = get_history()
        seen = [a for a in ads if a["id"] in history]
        unseen = [a for a in ads if a["id"] not in history]
        return seen, unseen
    
    
    def get_history():
        try:
            with open("seen.txt", "r") as f:
                return {l.rstrip() for l in f.readlines()}
        except:
            return set()
    
    

    También agregamos una función que nos permita distinguir los que ya mandamos (seen) de los nuevos (unseen).

    알림



    def notify(ad):
        bot = "YOUR_BOT_ID"
        room = "YOUR_CHAT_ROOM_ID"
        url = "https://api.telegram.org/bot{}/sendMessage?chat_id={}&text={}".format(bot, room, ad["url"])
        r = requests.get(url)
    

    Luego는 HTTP 포스트에 간단한 요청을 사용하여 url을 그룹 그룹에 포함합니다Telegram.

    Gracias a la función de "preview"de Telegram, los ads se muestran con una imagen de la propiedad:



    Por último sólo nos queda agregar los avisos notificados a seen.txt y listo.

    호스팅



    Ahora sólo necesitamos una máquina donde correrlo periódicamente. Por suerte AWS tiene un free tier que nos brinda una máquina básica por un mes, free.

    Si bien la virtual no es muy poderosa, para este simple script bista y sobra. Yo lo tengo corriendo con un cronjob que lo ejecuta cada 5분:

    # m h  dom mon dow   command
    */5 * * * * /home/ubuntu/propfinder/search_props.sh
    

    결론



    100개 라인의 스크립팅 푸디모스 하커와 스크래퍼 멀티 사이트, 5분 동안 공개된 채팅에서 가장 많은 정보를 제공합니다.

    Mucho más divertido (y menos frustrante) que metere periódicamente a los distintos sitios a ver si hay alguna novedad.

    좋은 웹페이지 즐겨찾기