Grote push
This commit is contained in:
parent
4bcf82fa3e
commit
847f6650e9
7 changed files with 175 additions and 42 deletions
|
@ -9,11 +9,11 @@ De bestandsextensie werd aangepast om te kunnen debuggen op zowel Windows als Li
|
|||
import cgi
|
||||
import json
|
||||
|
||||
from scraper import run, converteer
|
||||
from scraper import run
|
||||
|
||||
parameters = cgi.FieldStorage()
|
||||
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() # Lege lijn na headers
|
||||
|
|
|
@ -9,11 +9,24 @@ from bs4 import BeautifulSoup
|
|||
import requests
|
||||
|
||||
|
||||
def converteer(tekst, user=True):
|
||||
if user:
|
||||
return tekst.replace(' ', '_')
|
||||
def converteer(tekst, gebruiker=True):
|
||||
"""
|
||||
>>> converteer('Northwestern Europe')
|
||||
'Northwestern Europe'
|
||||
>>> converteer('Northwestern_Europe', False)
|
||||
'Northwestern_Europe'
|
||||
>>> converteer('Medchal%E2%80%93Malkajgiri_district')
|
||||
'Medchal–Malkajgiri district'
|
||||
>>> converteer('Medchal–Malkajgiri district', False)
|
||||
'Medchal%E2%80%93Malkajgiri_district'
|
||||
"""
|
||||
|
||||
from urllib import parse
|
||||
|
||||
if gebruiker:
|
||||
return parse.unquote(tekst).replace('_', ' ').split('#')[0]
|
||||
else:
|
||||
return tekst.replace('_', ' ')
|
||||
return parse.quote(tekst.replace(' ', '_'))
|
||||
|
||||
|
||||
def zoek_link(soep):
|
||||
|
@ -31,10 +44,19 @@ def zoek_link(soep):
|
|||
'High-level_programming_language'
|
||||
>>> zoek_link(BeautifulSoup(requests.get('https://en.wikipedia.org/wiki/Department_of_Standards_Malaysia').content, 'html.parser'))
|
||||
'Ministry_of_International_Trade_and_Industry_(Malaysia)'
|
||||
"""
|
||||
# TODO Zorg ervoor dat tekst schuin of vetjes ook nog herkend wordt
|
||||
>>> zoek_link(BeautifulSoup(requests.get('https://en.wikipedia.org/wiki/Malawi').content, 'html.parser'))
|
||||
'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
|
||||
|
||||
# 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.
|
||||
# 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.
|
||||
while link is None:
|
||||
|
@ -52,9 +74,10 @@ def zoek_link(soep):
|
|||
# Negeer linkjes in superscript, dus zoek enkel op het huidige niveau.
|
||||
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':
|
||||
|
||||
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
|
||||
if alinea is None:
|
||||
|
@ -110,42 +133,52 @@ def run(taal, start, stop):
|
|||
>>> 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']}
|
||||
>>> 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')
|
||||
{'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', 'Medchal–Malkajgiri 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
|
||||
>>> 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
|
||||
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.
|
||||
lijst = [converteer(start)] if start != 'Special:Random' else []
|
||||
lijst = [converteer(start, True)] if start != 'Special:Random' else []
|
||||
base = f"https://{taal}.wikipedia.org/wiki/"
|
||||
|
||||
while start != stop:
|
||||
|
||||
# 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.
|
||||
soep = BeautifulSoup(pagina.content, 'html.parser')
|
||||
|
||||
# Volgende link zoeken.
|
||||
start = zoek_link(soep)
|
||||
start = converteer(zoek_link(soep))
|
||||
|
||||
# TODO Dit verder uitwerken
|
||||
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
|
||||
nieuw = converteer(start.split('/')[-1], False)
|
||||
if nieuw in lijst:
|
||||
return {
|
||||
'error':
|
||||
f'Cyclus gedetecteerd op {nieuw}, het onafgewerkte pad zal niet worden toegevoegd aan het overzicht'
|
||||
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(nieuw)
|
||||
lijst.append(start)
|
||||
|
||||
return {'pad': lijst}
|
||||
|
|
41
cgi-bin/stresstest.py
Normal file
41
cgi-bin/stresstest.py
Normal 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
BIN
images/wikipedia_edit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
|
@ -2,18 +2,25 @@
|
|||
<html lang="HTML5">
|
||||
<head>
|
||||
<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>
|
||||
<body>
|
||||
<div id="top-bar">
|
||||
<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="einde">Eindpunt: </label><input type="text" id="einde" placeholder="Philosophy"/>
|
||||
<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/>
|
||||
|
||||
<h1>Phikipathia</h1>
|
||||
<h3>Philosophy Wikipedia Path visualiser</h3>
|
||||
</div>
|
||||
<div id="visualisatie">
|
||||
</div>
|
||||
<script src="index.js"></script>
|
||||
|
|
63
index.js
63
index.js
|
@ -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
|
||||
const taal = document.querySelector('#taal');
|
||||
const start = document.querySelector('#start');
|
||||
const einde = document.querySelector('#einde');
|
||||
const toevoegKnop = document.querySelector('#toevoegKnop');
|
||||
const visualisatie = document.querySelector('#visualisatie');
|
||||
const taal = document.getElementById('taal');
|
||||
const start = document.getElementById('start');
|
||||
const einde = document.getElementById('einde');
|
||||
const toevoegKnop = document.getElementById('toevoegKnop');
|
||||
const visualisatie = document.getElementById('visualisatie');
|
||||
|
||||
maakElementIn(getOrDefault(einde), visualisatie);
|
||||
let huidigeTaal;
|
||||
let huidigeDoel;
|
||||
|
||||
refreshTree();
|
||||
toevoegKnop.addEventListener('click', () => zoek());
|
||||
taal.addEventListener('input', () => inputWaarschuwing())
|
||||
einde.addEventListener('input', () => inputWaarschuwing());
|
||||
|
||||
/**
|
||||
* Zoek een
|
||||
* pad met scraper.py en voeg deze toe in de lijst.
|
||||
* Zoek een pad met python backend en voeg deze toe in de lijst.
|
||||
*/
|
||||
function zoek() {
|
||||
|
||||
|
@ -21,6 +25,8 @@ function zoek() {
|
|||
// paden tegelijk toegevoegd kunnen worden.
|
||||
toevoegKnop.disabled = true;
|
||||
|
||||
refreshTree();
|
||||
|
||||
const verzoek = { // Standaardwaarden gebruiken indien het veld leeg is.
|
||||
taal: getOrDefault(taal),
|
||||
start: getOrDefault(start),
|
||||
|
@ -30,14 +36,14 @@ function zoek() {
|
|||
fetch(`cgi-bin/init.py?data=${JSON.stringify(verzoek)}`)
|
||||
.then(antwoord => antwoord.json())
|
||||
.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.
|
||||
|
||||
}
|
||||
|
||||
function voegToe(data) {
|
||||
if (data.hasOwnProperty('error')) {
|
||||
alert(data.error);
|
||||
alert('↯ ' + data.error);
|
||||
} else {
|
||||
let pad = data.pad;
|
||||
|
||||
|
@ -58,21 +64,52 @@ function voegToe(data) {
|
|||
|
||||
// Nieuw element creëren (zonder toe te voegen aan het DOM).
|
||||
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 nieuw = document.createElement('li');
|
||||
nieuw.innerHTML = titel;
|
||||
nieuw.setAttribute('item', titel);
|
||||
wrap.appendChild(nieuw);
|
||||
|
||||
if (id !== undefined) {
|
||||
wrap.id = id;
|
||||
}
|
||||
|
||||
moeder.appendChild(wrap);
|
||||
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) {
|
||||
return element.value === '' ? element.getAttribute('placeholder') : element.value;
|
||||
}
|
||||
|
|
15
style.css
Normal file
15
style.css
Normal 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;
|
||||
}
|
Reference in a new issue