1
Fork 0

Grote push

This commit is contained in:
Tibo De Peuter 2022-05-19 15:43:18 +02:00
parent 4bcf82fa3e
commit 847f6650e9
7 changed files with 175 additions and 42 deletions

View file

@ -9,11 +9,11 @@ De bestandsextensie werd aangepast om te kunnen debuggen op zowel Windows als Li
import cgi import cgi
import json import json
from scraper import run, converteer from scraper import run
parameters = cgi.FieldStorage() parameters = cgi.FieldStorage()
data = json.loads(parameters.getvalue('data')) data = json.loads(parameters.getvalue('data'))
antwoord = run(data['taal'], converteer(data['start']), converteer(data['einde'])) antwoord = run(data['taal'], data['start'], data['einde'])
print("Content-Type: application/json") print("Content-Type: application/json")
print() # Lege lijn na headers print() # Lege lijn na headers

View file

@ -9,11 +9,24 @@ from bs4 import BeautifulSoup
import requests import requests
def converteer(tekst, user=True): def converteer(tekst, gebruiker=True):
if user: """
return tekst.replace(' ', '_') >>> converteer('Northwestern Europe')
'Northwestern Europe'
>>> converteer('Northwestern_Europe', False)
'Northwestern_Europe'
>>> converteer('Medchal%E2%80%93Malkajgiri_district')
'MedchalMalkajgiri district'
>>> converteer('MedchalMalkajgiri district', False)
'Medchal%E2%80%93Malkajgiri_district'
"""
from urllib import parse
if gebruiker:
return parse.unquote(tekst).replace('_', ' ').split('#')[0]
else: else:
return tekst.replace('_', ' ') return parse.quote(tekst.replace(' ', '_'))
def zoek_link(soep): def zoek_link(soep):
@ -31,10 +44,19 @@ def zoek_link(soep):
'High-level_programming_language' 'High-level_programming_language'
>>> zoek_link(BeautifulSoup(requests.get('https://en.wikipedia.org/wiki/Department_of_Standards_Malaysia').content, 'html.parser')) >>> zoek_link(BeautifulSoup(requests.get('https://en.wikipedia.org/wiki/Department_of_Standards_Malaysia').content, 'html.parser'))
'Ministry_of_International_Trade_and_Industry_(Malaysia)' 'Ministry_of_International_Trade_and_Industry_(Malaysia)'
""" >>> zoek_link(BeautifulSoup(requests.get('https://en.wikipedia.org/wiki/Malawi').content, 'html.parser'))
# TODO Zorg ervoor dat tekst schuin of vetjes ook nog herkend wordt 'Tumbuka_language'
lijsttypes = ['ul', 'ol'] # Lijsttypes die we kunnen gebruiken Maar eventueel als alternatief 'Landlocked_country' ??
>>> zoek_link(BeautifulSoup(requests.get('https://en.wikipedia.org/wiki/%27s-Gravenweg_168,_Kralingen').content, 'html.parser'))
'Kralingen'
"""
# Ik heb besloten om ook lijsttypes te kunnen doorzoeken op nuttige linkjes. Dit is strikt genomen tegen de
# beschrijving van de opgave, maar volgens https://en.wikipedia.org/wiki/Wikipedia:Getting_to_Philosophy lijkt dit
# de logische methode, dus ik besloot ook lijsten te ondersteunen, als extra uitdaging. Ik vermoedde dat de opgave
# van het project eerder <p> specifieerde om ons wat hoofdbreuk te besparen.
ondersteuning = ['p', 'ul', 'ol']
link = None link = None
# Navigeer naar het niveau op de pagina waarop we zullen zoeken. # Navigeer naar het niveau op de pagina waarop we zullen zoeken.
@ -43,7 +65,7 @@ def zoek_link(soep):
# Niet recursief zoeken om niet in een tabel of iets dergelijke vast te komen. # Niet recursief zoeken om niet in een tabel of iets dergelijke vast te komen.
# Het niveau onder 'mw-parser-output' is wat we nodig hebben en waar alle nodige alinea's in staan. # Het niveau onder 'mw-parser-output' is wat we nodig hebben en waar alle nodige alinea's in staan.
alinea = soep.find(['p', lijsttypes], recursive=False) alinea = soep.find(ondersteuning, recursive=False)
# Ga steeds verder omlaag (niet dieper) totdat er een geldige link is gevonden. # Ga steeds verder omlaag (niet dieper) totdat er een geldige link is gevonden.
while link is None: while link is None:
@ -52,9 +74,10 @@ def zoek_link(soep):
# Negeer linkjes in superscript, dus zoek enkel op het huidige niveau. # Negeer linkjes in superscript, dus zoek enkel op het huidige niveau.
potentieel = alinea.find('a') potentieel = alinea.find('a')
# Spans negeren is redelijk enkel en alleen om coördinaat stukjes te vermijden.
while potentieel is None or alinea.findChild().name == 'span': while potentieel is None or alinea.findChild().name == 'span':
alinea = alinea.findNextSibling(['p', lijsttypes]) alinea = alinea.findNextSibling(ondersteuning)
# Het zou kunnen dat de bewerking hierboven ervoor zorgt dat we op het einde van de pagina zijn # Het zou kunnen dat de bewerking hierboven ervoor zorgt dat we op het einde van de pagina zijn
if alinea is None: if alinea is None:
@ -110,42 +133,52 @@ def run(taal, start, stop):
>>> run('en', "Belgium", "Philosophy") >>> run('en', "Belgium", "Philosophy")
{'pad': ['Belgium', 'Northwestern Europe', 'Subregion', 'Region', 'Geography', 'Science', 'Scientific method', 'Empirical evidence', 'Proposition', 'Logic', 'Reason', 'Consciousness', 'Sentience', 'Emotion', 'Mental state', 'Mind', 'Phenomenon', 'Immanuel Kant', 'Philosophy']} {'pad': ['Belgium', 'Northwestern Europe', 'Subregion', 'Region', 'Geography', 'Science', 'Scientific method', 'Empirical evidence', 'Proposition', 'Logic', 'Reason', 'Consciousness', 'Sentience', 'Emotion', 'Mental state', 'Mind', 'Phenomenon', 'Immanuel Kant', 'Philosophy']}
>>> run('en', 'Department of Standards Malaysia', 'Philosophy') >>> run('en', 'Department of Standards Malaysia', 'Philosophy')
{'pad': ['Department_of_Standards_Malaysia', 'Ministry of International Trade and Industry (Malaysia)', 'Ministry (government department)', 'Executive (government)', 'Government', 'State (polity)', 'Germans', 'Germany', 'Central Europe', 'Europe', 'Continent', 'Landmass', 'Region', 'Geography', 'Science', 'Scientific method', 'Empirical evidence', 'Proposition', 'Logic', 'Reason', 'Consciousness', 'Sentience', 'Emotion', 'Mental state', 'Mind', 'Phenomenon', 'Immanuel Kant', 'Philosophy']} {'pad': ['Department of Standards Malaysia', 'Ministry of International Trade and Industry (Malaysia)', 'Ministry (government department)', 'Executive (government)', 'Government', 'State (polity)', 'Germans', 'Germany', 'Central Europe', 'Europe', 'Continent', 'Landmass', 'Region', 'Geography', 'Science', 'Scientific method', 'Empirical evidence', 'Proposition', 'Logic', 'Reason', 'Consciousness', 'Sentience', 'Emotion', 'Mental state', 'Mind', 'Phenomenon', 'Immanuel Kant', 'Philosophy']}
>>> run('en', 'Malkajgiri mandal', 'Philosophy') >>> run('en', 'Malkajgiri mandal', 'Philosophy')
{'pad': ['Malkajgiri_mandal', 'Medchal%E2%80%93Malkajgiri district', 'District', 'Administrative division', 'Sovereign state', 'Polity', 'Politics', 'Decision-making', 'Psychology', 'Science', 'Scientific method', 'Empirical evidence', 'Proposition', 'Logic', 'Reason', 'Consciousness', 'Sentience', 'Emotion', 'Mental state', 'Mind', 'Phenomenon', 'Immanuel Kant', 'Philosophy']} {'pad': ['Malkajgiri mandal', 'MedchalMalkajgiri district', 'District', 'Administrative division', 'Sovereign state', 'Polity', 'Politics', 'Decision-making', 'Psychology', 'Science', 'Scientific method', 'Empirical evidence', 'Proposition', 'Logic', 'Reason', 'Consciousness', 'Sentience', 'Emotion', 'Mental state', 'Mind', 'Phenomenon', 'Immanuel Kant', 'Philosophy']}
Loops Loops
>>> run('nl', 'België', 'Philosophy') >>> run('nl', 'België', 'Philosophy')
{'error': "Cyclus gedetecteerd op 'Wetenschap', het onafgewerkte pad zal niet worden toegevoegd aan het overzicht."}
>>> run('en', 'Tom Inglesby', 'Contract failure')
{'pad': ['Tom Inglesby', 'Johns Hopkins Center for Health Security', 'Nonprofit organization', 'Contract failure']}
Doodlopende eindes Doodlopende eindes
TODO Voorbeelden zoeken
Foute linkjes
>>> run('en', 'Deze pagina bestaat niet', 'Philosophy')
{'error': "Er ging iets fout bij het inladen van 'Deze pagina bestaat niet'. Bestaat de website?"}
""" """
# Negeer de 'random' waarde als er op deze manier gestart wordt. # Negeer de 'random' waarde als er op deze manier gestart wordt.
lijst = [converteer(start)] if start != 'Special:Random' else [] lijst = [converteer(start, True)] if start != 'Special:Random' else []
base = f"https://{taal}.wikipedia.org/wiki/" base = f"https://{taal}.wikipedia.org/wiki/"
while start != stop: while start != stop:
# Pagina inladen. # Pagina inladen.
pagina = requests.get(base + start) pagina = requests.get(base + converteer(start, False))
# Stoppen indien het inladen van de pagina niet lukte.
if pagina.status_code != 200:
return {'error': f"Er ging iets fout bij het inladen van '{lijst[-1]}'. Bestaat de website?"}
# Verwerken. # Verwerken.
soep = BeautifulSoup(pagina.content, 'html.parser') soep = BeautifulSoup(pagina.content, 'html.parser')
# Volgende link zoeken. # Volgende link zoeken.
start = zoek_link(soep) start = converteer(zoek_link(soep))
# TODO Dit verder uitwerken
if start is None: if start is None:
return {'error': f'Er konden geen nieuwe links meer gevonden worden op {lijst[-1]}'} return {'error': f"Er konden geen nieuwe links meer gevonden worden op '{lijst[-1]}'"}
# Cyclus detecteren # Cyclus detecteren
nieuw = converteer(start.split('/')[-1], False) if start in lijst:
if nieuw in lijst: return {'error':
return { f"Cyclus gedetecteerd op '{start}', startende vanaf '{lijst[0]}'. Het onafgewerkte pad zal niet worden toegevoegd aan het overzicht. "
'error': }
f'Cyclus gedetecteerd op {nieuw}, het onafgewerkte pad zal niet worden toegevoegd aan het overzicht'
}
lijst.append(nieuw) lijst.append(start)
return {'pad': lijst} return {'pad': lijst}

41
cgi-bin/stresstest.py Normal file
View file

@ -0,0 +1,41 @@
#!/usr/bin/env python3
"""
Dit script is enkel en alleen bedoeld om heel veel willekeurige pagina's te kunnen testen en
enkel degene eruit te halen die falen (en dus niet correct afgehandeld worden).
"""
from bs4 import BeautifulSoup
import requests
from scraper import converteer, zoek_link
def run(taal, start, stop):
lijst = [converteer(start, True)] if start != 'Special:Random' else []
base = f"https://{taal}.wikipedia.org/wiki/"
while start != stop:
# Dit is het enigste dat we aanpassen.
print(lijst[-1] if len(lijst) != 0 else [])
pagina = requests.get(base + converteer(start, False))
if pagina.status_code != 200:
return {'error': f"Er ging iets fout bij het inladen van '{lijst[-1]}'. Bestaat de website?"}
soep = BeautifulSoup(pagina.content, 'html.parser')
start = converteer(zoek_link(soep))
if start is None:
return {'error': f"Er konden geen nieuwe links meer gevonden worden op '{lijst[-1]}'"}
if start in lijst:
return {'error':
f"Cyclus gedetecteerd op '{start}', startende vanaf '{lijst[0]}'. Het onafgewerkte pad zal niet worden toegevoegd aan het overzicht. "
}
lijst.append(start)
return {'pad': lijst}
antwoord = run('en', 'Special:Random', 'Philosophy')
while 'pad' in antwoord or antwoord['error'].startswith('Cyclus'):
antwoord = run('en', 'Special:Random', 'Philosophy')
print(antwoord['error'])

BIN
images/wikipedia_edit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View file

@ -2,20 +2,27 @@
<html lang="HTML5"> <html lang="HTML5">
<head> <head>
<meta charset=UTF-8> <meta charset=UTF-8>
<title>Phikipathia - Philosophy Wikipedia Path</title> <title>Phikipathia</title>
<link rel="icon" href="./images/wikipedia_edit.png">
<link rel="stylesheet" href="style.css">
</head> </head>
<body> <body>
<div id="top-bar">
<label for="taal">Taal: </label><input type="text" id="taal" placeholder="en"/> <label for="taal">Taal: </label><input type="text" id="taal" placeholder="en"/>
<label for="start">Startpagina: </label><input type="text" id="start" placeholder="Special:Random"/> <label for="start">Startpagina: </label><input type="text" id="start" placeholder="Special:Random"/>
<label for="einde">Eindpunt: </label><input type="text" id="einde" placeholder="Philosophy"/> <label for="einde">Eindpunt: </label><input type="text" id="einde" placeholder="Philosophy"/>
<button type="button" id="toevoegKnop">Voeg toe</button> <button type="button" id="toevoegKnop">Voeg toe</button>
<p id="waarschuwing" hidden="hidden">
De huidige boom zal overschreven worden bij een nieuwe toevoeging.
</p>
<hr/> <hr/>
<h1>Phikipathia</h1> <h1>Phikipathia</h1>
<h3>Philosophy Wikipedia Path visualiser</h3> <h3>Philosophy Wikipedia Path visualiser</h3>
<div id="visualisatie"> </div>
</div> <div id="visualisatie">
<script src="index.js"></script> </div>
<script src="index.js"></script>
</body> </body>
</html> </html>

View file

@ -1,19 +1,23 @@
// TODO decodeURIComponent(String) // TODO De huidige lijst meegeven en controleren tijdens het opstellen zodat er gestopt wordt vanaf er een titel gevonden is
// Initialiseer de webpagina // Initialiseer de webpagina
const taal = document.querySelector('#taal'); const taal = document.getElementById('taal');
const start = document.querySelector('#start'); const start = document.getElementById('start');
const einde = document.querySelector('#einde'); const einde = document.getElementById('einde');
const toevoegKnop = document.querySelector('#toevoegKnop'); const toevoegKnop = document.getElementById('toevoegKnop');
const visualisatie = document.querySelector('#visualisatie'); const visualisatie = document.getElementById('visualisatie');
maakElementIn(getOrDefault(einde), visualisatie); let huidigeTaal;
let huidigeDoel;
refreshTree();
toevoegKnop.addEventListener('click', () => zoek()); toevoegKnop.addEventListener('click', () => zoek());
taal.addEventListener('input', () => inputWaarschuwing())
einde.addEventListener('input', () => inputWaarschuwing());
/** /**
* Zoek een * Zoek een pad met python backend en voeg deze toe in de lijst.
* pad met scraper.py en voeg deze toe in de lijst.
*/ */
function zoek() { function zoek() {
@ -21,6 +25,8 @@ function zoek() {
// paden tegelijk toegevoegd kunnen worden. // paden tegelijk toegevoegd kunnen worden.
toevoegKnop.disabled = true; toevoegKnop.disabled = true;
refreshTree();
const verzoek = { // Standaardwaarden gebruiken indien het veld leeg is. const verzoek = { // Standaardwaarden gebruiken indien het veld leeg is.
taal: getOrDefault(taal), taal: getOrDefault(taal),
start: getOrDefault(start), start: getOrDefault(start),
@ -30,14 +36,14 @@ function zoek() {
fetch(`cgi-bin/init.py?data=${JSON.stringify(verzoek)}`) fetch(`cgi-bin/init.py?data=${JSON.stringify(verzoek)}`)
.then(antwoord => antwoord.json()) .then(antwoord => antwoord.json())
.then(data => voegToe(data)) .then(data => voegToe(data))
.catch(reason => alert(reason)) .catch(reason => alert('‼ ' + reason))
.finally(() => toevoegKnop.disabled = false); // Herstel de knop. Ook als er ondertussen iets mis ging. .finally(() => toevoegKnop.disabled = false); // Herstel de knop. Ook als er ondertussen iets mis ging.
} }
function voegToe(data) { function voegToe(data) {
if (data.hasOwnProperty('error')) { if (data.hasOwnProperty('error')) {
alert(data.error); alert('↯ ' + data.error);
} else { } else {
let pad = data.pad; let pad = data.pad;
@ -58,21 +64,52 @@ function voegToe(data) {
// Nieuw element creëren (zonder toe te voegen aan het DOM). // Nieuw element creëren (zonder toe te voegen aan het DOM).
for (let item of pad.reverse()) { for (let item of pad.reverse()) {
moeder = maakElementIn(item, moeder); moeder = maakIn(item, moeder);
} }
} }
} }
function maakElementIn(titel, moeder) { /**
* Maakt een element aan binnen een ander element, en geeft het nieuwste (diepste) element terug.
*/
function maakIn(titel, moeder, id) {
let wrap = document.createElement('ul'); let wrap = document.createElement('ul');
let nieuw = document.createElement('li'); let nieuw = document.createElement('li');
nieuw.innerHTML = titel; nieuw.innerHTML = titel;
nieuw.setAttribute('item', titel); nieuw.setAttribute('item', titel);
wrap.appendChild(nieuw); wrap.appendChild(nieuw);
if (id !== undefined) {
wrap.id = id;
}
moeder.appendChild(wrap); moeder.appendChild(wrap);
return nieuw; return nieuw;
} }
/**
* Probeer of de huidige boom verwijderd moet worden en voeg de bestemming reeds toe aan de nieuwe boom.
*/
function refreshTree() {
if (huidigeDoel !== getOrDefault(einde) || huidigeTaal !== getOrDefault(taal)) {
huidigeTaal = getOrDefault(taal);
huidigeDoel = getOrDefault(einde);
visualisatie.innerHTML = '';
maakIn(huidigeDoel, visualisatie, 'wortel');
inputWaarschuwing();
}
}
/**
* Toon of verberg een speciale waarschuwing die zegt of de huidige boom verwijderd zal worden
* bij een nieuwe toevoeging.
*/
function inputWaarschuwing() {
document.getElementById('waarschuwing').hidden = huidigeTaal === getOrDefault(taal) && huidigeDoel === getOrDefault(einde);
}
function getOrDefault(element) { function getOrDefault(element) {
return element.value === '' ? element.getAttribute('placeholder') : element.value; return element.value === '' ? element.getAttribute('placeholder') : element.value;
} }

15
style.css Normal file
View file

@ -0,0 +1,15 @@
li ul {
/* Zorg ervoor dat de kinderelementen met hun bolletje onder de eerste letter van het vorige element staan. */
margin: 0.2vh 1ch;
padding: 0.2vh 1vw;
}
ul {
/* list-style-type: symbols("↪");*/
list-style-type: symbols("⬈");
}
ul#wortel {
padding: 0;
list-style-type: none;
}