Compare commits
64 Commits
loop-patch
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c9bfa60d8 | |||
| 341bdd90ac | |||
| 80f4f3e9fc | |||
| a014444305 | |||
| 5c09b714f5 | |||
| 6437960ec8 | |||
| 026b71abc9 | |||
| b743afed4e | |||
| 4adba7d017 | |||
| 57cdc465b8 | |||
| c81acebd9a | |||
| 37f04d5b44 | |||
| 21d1e48b62 | |||
| 7551806620 | |||
| 277f12e4ea | |||
| 5a7767dd82 | |||
| 11d20be5f9 | |||
| ded745ef17 | |||
| bae3c7f21d | |||
| 677485e355 | |||
| faba11986b | |||
| c26454e02a | |||
| 8d776b81c5 | |||
| 717155e4bb | |||
| 7596a3e67c | |||
| 10e190c673 | |||
| 7452978f65 | |||
| 2271c39601 | |||
| 9ca7f1793d | |||
| ae050b36de | |||
| 9b3af3aa06 | |||
| b065873608 | |||
| c0abc889c4 | |||
| 2a3fddea3d | |||
| a6eeb26534 | |||
| bfd7e87ece | |||
| 02fdb04de2 | |||
| 3fb3d5c6b7 | |||
| cc7700ad58 | |||
| 87c95135c1 | |||
| 12430fcd46 | |||
| 48fdda355c | |||
| 9b3d9b3a65 | |||
| c9c0eabe4e | |||
| 7aed398551 | |||
| b8c65fc17f | |||
| e789e63434 | |||
| 53ee839021 | |||
| da3522aa76 | |||
| aaf4818dbc | |||
| 371d61de66 | |||
| ef20eee6c9 | |||
| 85ad0dd3b2 | |||
| 9836da5921 | |||
| 5470667776 | |||
| 1919eeb88b | |||
| 183c78a769 | |||
| 730e6b6644 | |||
| 809cb9a766 | |||
| fa8aff500d | |||
| 3cea1cbd3b | |||
| dd9721ef16 | |||
| 724ba9923c | |||
| 6f7e9e11be |
5
LICENSE
5
LICENSE
@@ -1,5 +0,0 @@
|
|||||||
Copyright (C) YEAR by AUTHOR EMAIL
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
147
README.md
147
README.md
@@ -1,114 +1,49 @@
|
|||||||
# CENANDOODLE
|
## SCRAPE JUST EAT
|
||||||
|
|
||||||
||| Ordinare cibo con doodle in rete locale o anche no |||
|
Scarica liberamente tutti i dati e il menu di un ristorante presente su JustEat
|
||||||
|
|
||||||
||| Doodle condiviso su rete locale per ordinare e organizzare cibo e bevande (se previste) |||
|
## Dati raccolti:
|
||||||
|
- `Prodotti:`
|
||||||
|
- `Nome`
|
||||||
|
- `Descrizione`
|
||||||
|
- `Numero dei pezzi`
|
||||||
|
- `Prezzo`
|
||||||
|
- `Ristorante:`
|
||||||
|
- `Nome`
|
||||||
|
- `Via`
|
||||||
|
- `Numero di telefono`
|
||||||
|
- `Disponibilità consegna`
|
||||||
|
- `Disponiilità ritiro al ristorante`
|
||||||
|
- `Costo consegna`
|
||||||
|
- `Ordine minimo`
|
||||||
|
|
||||||
setup-sh -> installa requisiti (tutti pip3 tra cui jawanndenn)
|
-----------------------------------
|
||||||
|
|
||||||
scrapeJE.py -> scrapa e stora dentro a 4 liste il nome prodotto, la descrizione, il numero dei pezzi(es 5 falefel per x€) e il prezzo. Infine crea jwndn.json che è un formattato leggibile da jawanndenn con il nome del ristorante e il nome dei prodotti.
|
## INSTALLAZIONE
|
||||||
|
|
||||||
start.sh -> avvia scrapeJE.py e poi cerca di usare (in vano, nel senso che nonfunziona) la funzione di javanndenn che carica un file json
|
Scarica il git
|
||||||
|
```bash
|
||||||
----------------------------------------
|
#Scarica il git
|
||||||
|
git clone https://repo.esiliati.org/scossa/scrapeje.git
|
||||||
# JAWANNDENN, UN GIT OPENSOURCE PER DOODLE
|
#Entra nella cartella di scrapeje
|
||||||
|
cd scrapeje
|
||||||
Git
|
```
|
||||||
https://github.com/hartwork/jawanndenn
|
|
||||||
|
|
||||||
|
|
||||||
Si installa
|
|
||||||
|
|
||||||
pip3 install jawanndenn --user
|
|
||||||
|
|
||||||
o con git clone
|
|
||||||
|
|
||||||
git clone https://github.com/hartwork/jawanndenn
|
|
||||||
./setup.py install --user
|
|
||||||
|
|
||||||
si lancia
|
|
||||||
|
|
||||||
jawanndenn
|
|
||||||
La tua macchina quindi hosta il doodle all indirizzo 127.0.0.1:8080 e si avvia una copia di questa demo qui https://jawanndenn.de/
|
|
||||||
|
|
||||||
jawanndenn --help:
|
|
||||||
--debug Enable debug mode (default: disabled)
|
|
||||||
--host HOST Hostname or IP address to listen at (dfault 127.0.0.1)
|
|
||||||
--port PORT Port to listen at (default: 8080)
|
|
||||||
--url-prefix PATH Path to prepend to URLs (default: "")
|
|
||||||
--database-sqlite3 FILE File to write the database to (default: ~/jawanndenn.sqlite3)
|
|
||||||
--django-secret-key-file FILE File to use for Django secret key data (default: ~/jawanndenn.secret_key)
|
|
||||||
|
|
||||||
data import/export arguments:
|
|
||||||
--dumpdata Dump a JSON export of the database to standard output, then quit.
|
|
||||||
--loaddata FILE.json Load a JSON export of the database from FILE.json, then quit.
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
# DA FARE PER IMPLEMENTARE CENANDOODLE:
|
|
||||||
|
|
||||||
# [AVVIARE JAWANNDENN CON jwndn.json PRECARICATO]
|
|
||||||
"jawandenn --loaddata file.json" promette di caricare un json precaricato nel doodle ma invece da warnings e errori simili a questi:
|
|
||||||
|
|
||||||
WARNINGS:
|
|
||||||
jawanndenn.Ballot: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
|
|
||||||
HINT: Configure the DEFAULT_AUTO_FIELD setting or the AppConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
|
|
||||||
Operations to perform:
|
|
||||||
Apply all migrations: admin, auth, contenttypes, jawanndenn, sessions
|
|
||||||
Running migrations:
|
|
||||||
No migrations to apply.
|
|
||||||
Importing JSON dump -- this may take a few seconds...
|
|
||||||
System check identified some issues:
|
|
||||||
|
|
||||||
WARNINGS:
|
|
||||||
jawanndenn.Ballot: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
|
|
||||||
HINT: Configure the DEFAULT_AUTO_FIELD setting or the AppConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
|
|
||||||
File "/home/$USER/.local/lib/python3.9/site-packages/django/core/serializers/json.py", line 70, in Deserializer
|
|
||||||
yield from PythonDeserializer(objects, **options)
|
|
||||||
File "/home/$USER/.local/lib/python3.9/site-packages/django/core/serializers/python.py", line 103, in Deserializer
|
|
||||||
Model = _get_model(d["model"])
|
|
||||||
TypeError: string indices must be integers
|
|
||||||
|
|
||||||
The above exception was the direct cause of the following exception:
|
|
||||||
Traceback (most recent call last):
|
|
||||||
"/home/$USER/.local/lib/python3.9/site-packages/django/core/serializers/json.py", line 74, in Deserializer
|
|
||||||
raise DeserializationError() from exc
|
|
||||||
django.core.serializers.base.DeserializationError: Problem installing fixture '/home/sco/Cenandoodle/jwndn.json':
|
|
||||||
"Fatayer con Spinaci"
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# [AGGIUNGERE PIU PEZZI DELLO STESSO PRODOTTO PER SINGOLO UTENTE]
|
|
||||||
|
|
||||||
scritto dentro a /home/$USER/jawanndenn/jawanndenn/static/js/pool.js c'è:
|
|
||||||
|
|
||||||
var VOTED_YES_CLASS = 'votedYes';
|
|
||||||
var VOTED_NO_CLASS = 'votedNo';
|
|
||||||
var YET_TO_VOTE_CLASS = 'yetToVote';
|
|
||||||
|
|
||||||
stavo cercando di capire come aggiungere un doppio, triplo, quadruplo... voto. In modo da "votare" ovver acquistare/aggiungere ad esempio DUE fatayer al formaggio per singolo user
|
|
||||||
|
|
||||||
# [AGGIUNGERE PREZZI DEL PRODOTTO ]
|
|
||||||
|
|
||||||
Credo si faccia sempre con /home/$USER/jawanndenn/jawanndenn/static/js/pool.js.
|
|
||||||
Una possibilità potrebbe essere quella di implementare aggiungendo le liste(prezz o, desc, npezzi) nel javascript facendole comparire tramite un mouseHover. Oppure il prezzo lo si potrebbe aggiungere accanto al nome (e quindi in jwndn.json)
|
|
||||||
|
|
||||||
# [GESTIRE LA QUESTIONE DEI PRODOTTI NON DISPONIBILI]
|
|
||||||
|
|
||||||
Trovare un modo per determinare quando i prodotti non sono diponibili, eliminandoli dall inclusione del json oppure specificando il "non disponibile"
|
|
||||||
|
|
||||||
# [PARSARE IL NUMERO DI TELEFONO]
|
|
||||||
|
|
||||||
Per ora so soltanto che alla riga 870 dell html parsato, all interno di uno "< script >" C'è il numero di telefono in forma "allergenPhoneNumber":"3389529446" (o per lo meno così è per Aleppo). Trovare poi un moodo di visualizzarlo, quasi sicuramente nel "title" del json così da visualizzarlo acconto del nome del ristorante.
|
|
||||||
|
|
||||||
# [CALCOLARE E VISUALIZZARE IL PREZZO SINGOLO E TOTALE]
|
|
||||||
|
|
||||||
Trovare un modo per calcolare il prezzo del singolo user e il prezzo totale da dare al rider
|
|
||||||
|
|
||||||
|
Installa requirement
|
||||||
|
```bash
|
||||||
|
#Concedi i permessi di esecuzione al setup
|
||||||
|
chmod +x ./setup.sh
|
||||||
|
#Esegui il setup
|
||||||
|
./setup.sh
|
||||||
|
```
|
||||||
|
## UTILIZZO
|
||||||
|
lancia ScrapeJE
|
||||||
|
```bash
|
||||||
|
python3 scrapeje.py
|
||||||
|
```
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
|
||||||
|
||| Ordinare cibo in rete locale o su servizio hostato. A favore del cliente e del ristoratore in termini economici, evitanto commissioni intermediare, ma senza rinunciare alla comodità dei clic <br>
|
||||||
|
||| Aggiungere più pezzi dello stesso prodotto per singolo utente, <br>
|
||||||
|
||| calcolare e visualizzare il prezzo del singolo utente e il totale da dare al rider. <br>
|
||||||
115
ScrapeJE.py
115
ScrapeJE.py
@@ -1,115 +0,0 @@
|
|||||||
import requests
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
import cloudscraper
|
|
||||||
import json
|
|
||||||
|
|
||||||
nome=[]
|
|
||||||
desc=[]
|
|
||||||
npezzi=[]
|
|
||||||
prezzo=[]
|
|
||||||
|
|
||||||
#prende l url della pagina justeat del ristorante in input
|
|
||||||
#linkJE = input('link della pagina justeat del ristorante: ') #decommenta per input manuale
|
|
||||||
|
|
||||||
#scrape html
|
|
||||||
scraper = cloudscraper.create_scraper(browser={'browser': 'firefox','platform': 'windows','mobile': False})
|
|
||||||
#page = scraper.get(linkJE).content #usa input manuale
|
|
||||||
page = scraper.get("https://www.justeat.it/restaurants-saporedialeppo/menu").content #usa input automatico
|
|
||||||
#crea il file html
|
|
||||||
with open('JEmenu.html', 'wb') as f:
|
|
||||||
f.write(page)
|
|
||||||
|
|
||||||
#apre e legge il file
|
|
||||||
with open('JEmenu.html', 'rb') as f:
|
|
||||||
page = f.read()
|
|
||||||
|
|
||||||
#parser
|
|
||||||
soup = BeautifulSoup(page, "html.parser")
|
|
||||||
menu = soup.find(attrs={"data-test-id": "menu-item"})
|
|
||||||
|
|
||||||
|
|
||||||
#Stora nome ristorante
|
|
||||||
nrist=soup.title.text[8:-32]
|
|
||||||
menu.find(attrs={"allergenPhoneNumber": "menu-item-name"})
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
#Stora il numero di telfono del ristorante
|
|
||||||
#info-> alla riga 870 dell html, all interno di uno <script> c'è il numero in forma-> "allergenPhoneNumber":"3389529446" (es riferito a quando si scrapa aleppo)
|
|
||||||
#tel=
|
|
||||||
##
|
|
||||||
|
|
||||||
|
|
||||||
#cicla le schede prodotto
|
|
||||||
for menu in soup.find_all(attrs={"data-test-id": "menu-item"}):
|
|
||||||
att=menu
|
|
||||||
#riempie la lista "nome"
|
|
||||||
for att in menu.find(attrs={"data-test-id": "menu-item-name"}):
|
|
||||||
if att != " ":
|
|
||||||
nome.append(att.lstrip().splitlines()[0])
|
|
||||||
|
|
||||||
#riempie la lista "desc"
|
|
||||||
att=menu.find("p", class_="c-menuItems-description")
|
|
||||||
if att != None:
|
|
||||||
for att in menu.find("p", class_="c-menuItems-description"):
|
|
||||||
desc.append(att.lstrip().splitlines()[0])
|
|
||||||
else:
|
|
||||||
desc.append(None)
|
|
||||||
|
|
||||||
#riempie la lista "prezzo"
|
|
||||||
for att in menu.find("p", class_="c-menuItems-price notranslate"):
|
|
||||||
prezzo.append(att.lstrip().splitlines()[0])
|
|
||||||
|
|
||||||
#riempie la lista "npezzi"
|
|
||||||
att=menu.find_all(attrs={"data-test-id": "menu-item-description"})
|
|
||||||
if att != None:
|
|
||||||
if menu.text.find("pezzo") > 0 or menu.text.find("pezzi") > 0:
|
|
||||||
npezzi.append(menu.text.splitlines()[7].lstrip())
|
|
||||||
else:
|
|
||||||
npezzi.append(None)
|
|
||||||
continue
|
|
||||||
|
|
||||||
#stampa liste
|
|
||||||
for x in range(len(nome)):
|
|
||||||
print("\n")
|
|
||||||
print(nome[x])
|
|
||||||
print(desc[x])
|
|
||||||
print(npezzi[x])
|
|
||||||
print(prezzo[x])
|
|
||||||
|
|
||||||
#stampa lunghezza liste e nome del risrorante # e numero di telefono
|
|
||||||
print("\n")
|
|
||||||
print(nrist)
|
|
||||||
#print(tel)
|
|
||||||
print("lista nome",len(nome))
|
|
||||||
print("lista desc:",len(desc))
|
|
||||||
print("lista npezzi:",len(npezzi))
|
|
||||||
print("lista prezzi:",len(prezzo)) #sono stringhe ovvero ci sono anche prezzi come "da 1,00 €" (servirà formattarla in double per poter fare i conti a fine doodle)
|
|
||||||
|
|
||||||
|
|
||||||
#Crea file json formattato per jawanndenn con la lista dei nomi dei prodotti
|
|
||||||
|
|
||||||
data = {"lifetime": "month", "equal_width": "true", "title": nrist, "options": nome}
|
|
||||||
|
|
||||||
print(json.dumps(data))
|
|
||||||
|
|
||||||
def writeListJSONFile(filepathname):
|
|
||||||
with open('jwndn.json', 'w') as f:
|
|
||||||
f.write(json.dumps(data))
|
|
||||||
|
|
||||||
|
|
||||||
writeListJSONFile('./jwndn.json')
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
#storare in "tel" il numero di telefono dle ristorante
|
|
||||||
#automatizzare l inserimento in jawandenn
|
|
||||||
|
|
||||||
#PS jawanndenn include la funzione per argomento
|
|
||||||
#"jawanndenn --loaddata FILE.json" --> Load a JSON export of the database from FILE.json, then quit.
|
|
||||||
|
|
||||||
#aggiungere la possibilità di mettere piu di un voto al doodle (ovvero prendere piu prodotti come es: 2 fatayer al formaggio)
|
|
||||||
|
|
||||||
#fare in modo che quando si passa il mouse sul nome del prodotto (nel doodle) compaiano descrizione, npezzi e prezzo
|
|
||||||
#forse per il prezzo trattamento diverso
|
|
||||||
#
|
|
||||||
383
scrapeje.py
Normal file
383
scrapeje.py
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
#IMPORTO MODULI
|
||||||
|
#selenium: scraper | bs4: parser | re: regex | os: interazione con os | shutil: interazione con la shell
|
||||||
|
from selenium import webdriver
|
||||||
|
from selenium.webdriver.support.ui import WebDriverWait
|
||||||
|
from selenium.webdriver.support import expected_conditions as EC
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from jinja2 import Template
|
||||||
|
import time
|
||||||
|
|
||||||
|
restaurant_url=''
|
||||||
|
driver=''
|
||||||
|
page = ''
|
||||||
|
nrist=''
|
||||||
|
restaurant_address=''
|
||||||
|
tel=''
|
||||||
|
result=''
|
||||||
|
soup = ''
|
||||||
|
nristmax = '0'
|
||||||
|
nome=[]
|
||||||
|
desc=[]
|
||||||
|
npezzi=[]
|
||||||
|
prezzo=[]
|
||||||
|
prezzoN=[]
|
||||||
|
|
||||||
|
|
||||||
|
def inputurl():
|
||||||
|
global restaurant_url
|
||||||
|
global nristmax
|
||||||
|
#INPUT
|
||||||
|
#prende l url della pagina justeat del ristorante in input
|
||||||
|
print ("\nesempio: https://www.justeat.it/restaurants-pizzeria-la-garganica-bologna/menu")
|
||||||
|
restaurant_url = input('INSERISCI IL LINK DELLA PAGINA DEL RISTORANTE: ')
|
||||||
|
# PER DEBUG
|
||||||
|
#restaurant_url = 'https://www.justeat.it/restaurants-pizzeriadelrondone-bologna/menu'
|
||||||
|
|
||||||
|
|
||||||
|
def animazione():
|
||||||
|
def typewriter(text, delay=0.1):
|
||||||
|
for letter in text:
|
||||||
|
print(letter, end='', flush=True)
|
||||||
|
time.sleep(delay)
|
||||||
|
print()
|
||||||
|
|
||||||
|
typewriter("▁ ▂ ▃ ▄ ▅ ▆ ▇ █ ▇ ▆ ▅ ▄ ▃ ▁", 0.09)
|
||||||
|
|
||||||
|
|
||||||
|
def scraper():
|
||||||
|
global driver
|
||||||
|
global page
|
||||||
|
global restaurant_url
|
||||||
|
|
||||||
|
#FIREFOX
|
||||||
|
opts = webdriver.FirefoxOptions()
|
||||||
|
opts.headless = True
|
||||||
|
driver = webdriver.Firefox(options=opts)
|
||||||
|
driver.get(restaurant_url)
|
||||||
|
|
||||||
|
#CHROMIUM/CHROME
|
||||||
|
# driver = webdriver.Chrome()
|
||||||
|
# driver.get(restaurant_url)
|
||||||
|
|
||||||
|
animazione()
|
||||||
|
|
||||||
|
wait = WebDriverWait(driver, 16)
|
||||||
|
wait.until(EC.presence_of_element_located((By.CLASS_NAME, "c-menuItems-price")))
|
||||||
|
|
||||||
|
page = driver.page_source
|
||||||
|
|
||||||
|
with open('JEmenu.html', 'w') as f:
|
||||||
|
f.write(page)
|
||||||
|
|
||||||
|
|
||||||
|
def parser():
|
||||||
|
global soup
|
||||||
|
with open('JEmenu.html', 'r') as f:
|
||||||
|
page = f.read()
|
||||||
|
|
||||||
|
soup = BeautifulSoup(page, "html.parser")
|
||||||
|
|
||||||
|
|
||||||
|
def stora_tutto():
|
||||||
|
global nome
|
||||||
|
global desc
|
||||||
|
global npezzi
|
||||||
|
global prezzo
|
||||||
|
global prezzoN
|
||||||
|
global soup
|
||||||
|
global nrist
|
||||||
|
global restaurant_address
|
||||||
|
global tel
|
||||||
|
global result
|
||||||
|
|
||||||
|
#Stora nome ristorante
|
||||||
|
nrist = soup.title.text[8:-32]
|
||||||
|
|
||||||
|
#Stora telefono del ristorante
|
||||||
|
pattern = re.compile(r'allergenPhoneNumber')
|
||||||
|
script_tags = soup.find_all('script', string=pattern)
|
||||||
|
pattern = re.compile(r'"allergenPhoneNumber":"(\d+)"')
|
||||||
|
tel = re.search(pattern, script_tags[0].next)
|
||||||
|
if tel:
|
||||||
|
tel = tel.group(1)
|
||||||
|
|
||||||
|
#Stato ristorante
|
||||||
|
restaurant_is_open = menu = soup.find(attrs={"data-js-test":"order-status-wrapper"}).text
|
||||||
|
restaurant_is_open = restaurant_is_open.replace('\n', ' ')
|
||||||
|
regex = r" {4,}"
|
||||||
|
result = re.split(regex, restaurant_is_open)
|
||||||
|
|
||||||
|
#indirizzo ristorante
|
||||||
|
restaurant_address = soup.find(attrs={"data-js-test":"header-restaurantAddress"}).text
|
||||||
|
|
||||||
|
#cicla le schede prodotto
|
||||||
|
menu = soup.find(attrs={"data-test-id": "menu-item"})
|
||||||
|
for menu in soup.find_all(attrs={"data-test-id": "menu-item"}):
|
||||||
|
att=menu
|
||||||
|
#riempie la lista "nome"
|
||||||
|
for att in menu.find(attrs={"data-test-id": "menu-item-name"}):
|
||||||
|
if att != type(None):
|
||||||
|
if att != " ":
|
||||||
|
nome.append(att.lstrip().splitlines()[0])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
#riempie la lista "desc"
|
||||||
|
att=menu.find("p", class_="c-menuItems-description")
|
||||||
|
if att != None:
|
||||||
|
for att in menu.find("p", class_="c-menuItems-description"):
|
||||||
|
desc.append(att.lstrip().splitlines()[0])
|
||||||
|
else:
|
||||||
|
desc.append(None)
|
||||||
|
|
||||||
|
#riempie la lista "prezzo"
|
||||||
|
for att in menu.find(attrs={"data-js-test": "menu-item-price"}):
|
||||||
|
#prezzo.append(att.lstrip().splitlines()[0])
|
||||||
|
counter=0
|
||||||
|
if att != " " and counter % 2 == 0:
|
||||||
|
prezzo.append(att.lstrip())
|
||||||
|
counter+=1
|
||||||
|
else:
|
||||||
|
counter+=1
|
||||||
|
continue
|
||||||
|
continue
|
||||||
|
|
||||||
|
#riempie la lista "npezzi"
|
||||||
|
att=menu.find_all(attrs={"data-test-id": "menu-item-description"})
|
||||||
|
if att != None:
|
||||||
|
if menu.text.find("pezzo") > 0 or menu.text.find("pezzi") > 0:
|
||||||
|
npezzi.append(menu.text.splitlines()[7].lstrip())
|
||||||
|
else:
|
||||||
|
npezzi.append(None)
|
||||||
|
continue
|
||||||
|
|
||||||
|
def parserdarubrica():
|
||||||
|
global parser
|
||||||
|
global stora_tutto
|
||||||
|
folder_path = ('./DATI_RUBRICA/')
|
||||||
|
for filename in os.listdir(folder_path):
|
||||||
|
if filename.startswith(scelta):
|
||||||
|
print(filename)
|
||||||
|
filename = filename.replace(' ', ' ')
|
||||||
|
print(filename)
|
||||||
|
shutil.copy (folder_path + filename, f'./JEmenu.html')
|
||||||
|
parser()
|
||||||
|
stora_tutto()
|
||||||
|
else:
|
||||||
|
print ("numero inesistente")
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
def stampa_liste(): #PER DEBUG
|
||||||
|
print("\n")
|
||||||
|
for x in range(len(nome)):
|
||||||
|
# print("\n")
|
||||||
|
print(nome[x])
|
||||||
|
print(desc[x])
|
||||||
|
print(npezzi[x])
|
||||||
|
print(prezzo[x])
|
||||||
|
|
||||||
|
|
||||||
|
def stampa_info():
|
||||||
|
print("-" * (len(desc)) + "\n")
|
||||||
|
print(nrist)
|
||||||
|
print(restaurant_address.strip())
|
||||||
|
print("Telefono:",tel,"\n")
|
||||||
|
|
||||||
|
doppione = ""
|
||||||
|
for i in range(len(result)):
|
||||||
|
if re.search(r"[a-zA-Z]", result[i]):
|
||||||
|
if (result[i]) == doppione:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
print(result[i])
|
||||||
|
elif re.search(r"\d", result[i]):
|
||||||
|
print(result[i], result[i+1])
|
||||||
|
doppione = (result[i+1])
|
||||||
|
print("\n" + "-" * (len(desc))+ "\n")
|
||||||
|
|
||||||
|
|
||||||
|
def genera_prezzoN():
|
||||||
|
#Genera la lista prezzoN[] che è un clone di "prezzo[] ma con i valori float anzichè string"
|
||||||
|
global prezzoN
|
||||||
|
prezzoN = prezzo.copy()
|
||||||
|
for i in range(len(prezzo)):
|
||||||
|
if "€" in prezzo[i]:
|
||||||
|
prezzoN[i] = float(prezzo[i].replace("€", "").replace(",", ".").replace("da ", ""))
|
||||||
|
elif "Non" in prezzo[i]:
|
||||||
|
prezzoN[i] = 0
|
||||||
|
prezzoN[i] = float(prezzoN[i])
|
||||||
|
else:
|
||||||
|
prezzoN[i] = 99999
|
||||||
|
# for x in range(len(nome)): #PER DEBUG
|
||||||
|
# print(prezzoN[x])
|
||||||
|
|
||||||
|
html=''
|
||||||
|
def genera_frontend():
|
||||||
|
# IMPOSTA E GENERA pagina2.html CON IL FILE htmlpage.html
|
||||||
|
global nome
|
||||||
|
global desc
|
||||||
|
global npezzi
|
||||||
|
global prezzo
|
||||||
|
global prezzoN
|
||||||
|
global html
|
||||||
|
with open("template.html", "r") as file:
|
||||||
|
template_content = file.read()
|
||||||
|
|
||||||
|
template = Template(template_content)
|
||||||
|
html = template.render(
|
||||||
|
nrist=nrist,
|
||||||
|
nome=nome,
|
||||||
|
desc=desc,
|
||||||
|
npezzi=npezzi,
|
||||||
|
prezzo=prezzo,
|
||||||
|
prezzoN=prezzoN
|
||||||
|
)
|
||||||
|
with open("pagina2.html", "w") as file:
|
||||||
|
file.write(html)
|
||||||
|
|
||||||
|
|
||||||
|
def salvainrubrica():
|
||||||
|
global nristmax
|
||||||
|
maxn=0
|
||||||
|
def trova_nuovo_numero():
|
||||||
|
global maxn
|
||||||
|
file_list = os.listdir('./DATI_RUBRICA')
|
||||||
|
number_list = []
|
||||||
|
# Estare il numero
|
||||||
|
for file_name in file_list:
|
||||||
|
if file_name[0].isdigit():
|
||||||
|
number_list.append(int(file_name.split('-')[0]))
|
||||||
|
# trova il massimo
|
||||||
|
if number_list:
|
||||||
|
max_number = max(number_list)
|
||||||
|
maxn=(max_number + 1)
|
||||||
|
|
||||||
|
if os.path.exists('rubrica.txt'):
|
||||||
|
#SE LA RUBRICA ESISTE
|
||||||
|
with open('rubrica.txt', 'a+') as rubrica:
|
||||||
|
rubrica.seek(0)
|
||||||
|
data = rubrica.read()
|
||||||
|
if restaurant_url not in data:
|
||||||
|
#QUANDO IL RISTORATE NON E' PRESENTE IN RUBRICA
|
||||||
|
saveit = input('Vuoi salvare il ristorante in rubrica? [Y|N] ')
|
||||||
|
#PER DEBUG
|
||||||
|
#saveit = "y"
|
||||||
|
if saveit.upper() in ['YES', 'Y', 'SI', 'S']:
|
||||||
|
os.makedirs("DATI_RUBRICA", exist_ok=True)
|
||||||
|
trova_nuovo_numero()
|
||||||
|
nristmax=(str(maxn) + "-" + nrist + '.html')
|
||||||
|
shutil.move ('JEmenu.html', f'./DATI_RUBRICA/{nristmax}')
|
||||||
|
if data:
|
||||||
|
rubrica.write('\n')
|
||||||
|
rubrica.write(nristmax + '\n')
|
||||||
|
rubrica.write(nrist + '\n')
|
||||||
|
rubrica.write(restaurant_url + '\n')
|
||||||
|
print ('\nIl ristorante"',nrist + '" è stato salvato in rubrica\n')
|
||||||
|
else:
|
||||||
|
#QUANDO IL RISTORATE E' GIA' PRESENTE IN RUBRICA
|
||||||
|
os.remove("JEmenu.html")
|
||||||
|
else:
|
||||||
|
#QUANDO IL RISTORATE E' GIA' PRESENTE IN RUBRICA
|
||||||
|
os.remove("JEmenu.html")
|
||||||
|
|
||||||
|
else:
|
||||||
|
#SE LA RUBRICA NON ESISTE
|
||||||
|
with open('rubrica.txt', 'a+') as rubrica:
|
||||||
|
rubrica.seek(0)
|
||||||
|
data = rubrica.read()
|
||||||
|
#CHIEDE SE SI VUOLE SALVARE ALTRIMENTI PULISCE
|
||||||
|
saveit = input('Vuoi salvare il ristorante in rubrica? [Y|N] ')
|
||||||
|
#PER DEBUG
|
||||||
|
#saveit = "y"
|
||||||
|
if saveit.upper() in ['YES', 'Y', 'SI', 'S']:
|
||||||
|
os.makedirs("DATI_RUBRICA", exist_ok=True)
|
||||||
|
nristmax=("1" + "-" + nrist + '.html')
|
||||||
|
shutil.move ('JEmenu.html', f'./DATI_RUBRICA/{nristmax}')
|
||||||
|
|
||||||
|
if data:
|
||||||
|
rubrica.write('\n')
|
||||||
|
rubrica.write(nristmax + '\n')
|
||||||
|
rubrica.write(nrist + '\n')
|
||||||
|
rubrica.write(restaurant_url + '\n')
|
||||||
|
print ('\nIl ristorante "' + nrist + '" è stato salvato in rubrica')
|
||||||
|
print ('(Riavvia lo script per ordinare da rubrica)\n')
|
||||||
|
else:
|
||||||
|
#PULISCE
|
||||||
|
os.remove("JEmenu.html")
|
||||||
|
os.remove("rubrica.txt")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################################
|
||||||
|
#############################################################################################
|
||||||
|
#############################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
if os.path.exists('rubrica.txt') and os.path.exists('./DATI_RUBRICA'):
|
||||||
|
|
||||||
|
#wr = input('\nVuoi vedere la rubrica? [Y|N] ')
|
||||||
|
wr = 's'
|
||||||
|
if wr.upper() in ['YES', 'Y', 'SI', 'S']:
|
||||||
|
print( '\n', os.listdir('./DATI_RUBRICA'), '\n')
|
||||||
|
|
||||||
|
#scelta = input("Scegli un numero esistente o premi Enter per metterre un link: ")
|
||||||
|
scelta = '1'
|
||||||
|
parserdarubrica()
|
||||||
|
|
||||||
|
else:
|
||||||
|
inputurl()
|
||||||
|
scraper()
|
||||||
|
parser()
|
||||||
|
stora_tutto()
|
||||||
|
driver.quit()
|
||||||
|
else:
|
||||||
|
inputurl()
|
||||||
|
scraper()
|
||||||
|
parser()
|
||||||
|
stora_tutto()
|
||||||
|
driver.quit()
|
||||||
|
|
||||||
|
stampa_liste()
|
||||||
|
stampa_info()
|
||||||
|
genera_prezzoN()
|
||||||
|
salvainrubrica()
|
||||||
|
genera_frontend()
|
||||||
|
|
||||||
|
driver = webdriver.Firefox()
|
||||||
|
animazione()
|
||||||
|
driver.get("file://" + os.path.abspath("pagina2.html"))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# #PER DEBUG
|
||||||
|
# for x in range(len(prezzoN)):
|
||||||
|
# print(prezzoN[x])
|
||||||
|
# print("\n" + "-" * 25 + "\n")
|
||||||
|
# print ("lista prezzo: ",len(prezzo))
|
||||||
|
# print ("lista prezzoN: ",len(prezzoN))
|
||||||
|
# print ("lista nome: ",len(nome))
|
||||||
|
# print("\n" + "-" * 25 + "\n")
|
||||||
|
|
||||||
|
|
||||||
|
# #PER DEBUG
|
||||||
|
#stampa lunghezza liste
|
||||||
|
# print("lista nome: ",len(nome))
|
||||||
|
# print("lista desc: ",len(desc))
|
||||||
|
# print("lista npezzi: ",len(npezzi))
|
||||||
|
# print("lista prezzi: ",len(prezzo)) #sono stringhe
|
||||||
|
# print("lista prezziN: ",len(prezzoN)) #sono numeri
|
||||||
|
# print("\n" + "-" * 25 + "\n")
|
||||||
|
|
||||||
|
#FA SCHIFO
|
||||||
|
# html += ' var popup = window.open("", "Popup", "width=200,height=100,top=" + ((window.innerHeight - 100) / 2) + ",left=" + ((window.innerWidth - 200) / 2));'
|
||||||
|
# html += ' popup.document.write("<p>Prodotto aggiunto</p>");'
|
||||||
|
# html += ' setTimeout(function(){ popup.close(); }, 1000);'
|
||||||
|
|
||||||
|
|
||||||
33
setup.sh
Normal file → Executable file
33
setup.sh
Normal file → Executable file
@@ -1,5 +1,32 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
pip3 install jawanndenn
|
|
||||||
|
echo "Installo i moduli python necessari nella cartella .venv"
|
||||||
|
python -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
echo
|
||||||
|
|
||||||
pip3 install requests
|
pip3 install requests
|
||||||
pip3 install BeautifulSoup4
|
pip3 install BeautifulSoup4
|
||||||
pip3 install cloudscraper
|
pip3 install selenium
|
||||||
|
|
||||||
|
#SCRAPEJE UTILIZZA I MODULI PREINSTALLATI:
|
||||||
|
# import re
|
||||||
|
# import os
|
||||||
|
# import shutil
|
||||||
|
#NON PIU UTILIZZATI:
|
||||||
|
# pip3 install colorama
|
||||||
|
# pip3 install cloudscraper
|
||||||
|
# pip3 install json
|
||||||
|
|
||||||
|
echo "Installo chromium (se non già installato) necessario per lo scrape"
|
||||||
|
echo
|
||||||
|
sudo apt update
|
||||||
|
if [ -f /etc/os-release ] && grep -q "NAME=\"Ubuntu\"" /etc/os-release; then
|
||||||
|
sudo apt install chromium-browser -y
|
||||||
|
else
|
||||||
|
sudo apt install chromium -y
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo "Attiva il virtualenv: source .venv/bin/activate"
|
||||||
|
echo "Poi lancia lo script: python3 scrapeje.py"
|
||||||
|
echo
|
||||||
|
|||||||
4
start.sh
4
start.sh
@@ -1,4 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
python3 ScrapeJE.py
|
|
||||||
wait 1
|
|
||||||
jawanndenn --loaddata jwndn.json
|
|
||||||
76
template.html
Normal file
76
template.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!-- <link rel="stylesheet" type="text/css" href="main.css" /> -->
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto auto;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.grid-item {
|
||||||
|
/* background-color: rgba(255, 255, 255, 0.8); */
|
||||||
|
border: 1px solid #ff8d1a;
|
||||||
|
padding: 20px;
|
||||||
|
/* font-size: 30px; */
|
||||||
|
text-align: center;
|
||||||
|
/* grid-column-start: 1;
|
||||||
|
grid-column-end: 3; */
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<body style="background-color: black; color: white">
|
||||||
|
<h1 style='text-align: center; color: #ff8d1a'>{{ nrist }} </h1>
|
||||||
|
|
||||||
|
<!-- <form id="usernameForm">
|
||||||
|
<input type="text" id="prodottiAggiunti" placeholder="Enter your username" />
|
||||||
|
<button type="button" onclick="addUser()">Add User</button>
|
||||||
|
</form> -->
|
||||||
|
</head>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
{% for index in range(nome|length) %}
|
||||||
|
<div class="grid-item">
|
||||||
|
<h2 style='text-align: center;'>{{ nome[index] }}</h2>
|
||||||
|
|
||||||
|
<div class="spazio">
|
||||||
|
<p style='text-align: center;'>{{ desc[index] }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p style='text-align: center;'>Npezzi: {{ npezzi[index] }}</p>
|
||||||
|
<p style='text-align: center;'>{{ prezzoN[index] }}€</p>
|
||||||
|
<div style='text-align: center;'><button style='font-size: 1.2em;' onclick="aggiungiProdotto('{{ nome[index] }}', '{{ prezzoN[index] }}')">+1</button></div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br><hr><h2>Prodotti aggiunti</h2>
|
||||||
|
<div id="prodottiAggiunti"></div>
|
||||||
|
<div id="total">Total: €<span id="totalValue">0.00</span></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var totalValue = 0;
|
||||||
|
function aggiungiProdotto(nome, prezzoN) {
|
||||||
|
var prodotto = nome + ' (' + Number(prezzoN).toFixed(2) + '€)';
|
||||||
|
var box = document.getElementById('prodottiAggiunti');
|
||||||
|
box.innerHTML += '<p>' + prodotto + ' <button onclick="rimuoviProdotto(this, ' + prezzoN + ')">-1</button></p>';
|
||||||
|
totalValue += parseFloat(prezzoN);
|
||||||
|
updateTotal();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTotal() {
|
||||||
|
document.getElementById('totalValue').innerText = totalValue.toFixed(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rimuoviProdotto(element, prezzoN) {
|
||||||
|
totalValue -= parseFloat(prezzoN);
|
||||||
|
element.parentNode.remove();
|
||||||
|
updateTotal();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user