Open rysson opened 5 years ago
Przemyślałem, div#info {p, p, p}
widzi mi się jako kolejne elementy w kolejności. Ale tyle w ramach <p>
.
Czyli {d, d, p, p}
dla P1 P2 D1 P3 D2
da [ D1
, D2
, P1
, P2
].
Stare zachowanie (tylko pierwszy) zostawiłem jako {{a, b}}
. Chyba w ogóle je wywalę.
Bardzo chętnie bym pomógł ale chyba nie mam startu do ciebie. Moja wiedza jest zbyt uboga :P Poza tym ciężko to przedyskutować pisząc. To trzeba usiąść na spokojnie.. :D
A ja nawet nie wiem o czym ty do mnie piszesz....
Znaczy, że źle o tym napisałem.
Na razie ciekawostka, parseDOM() jest na wiki: https://kodi.wiki/view/Add-on:Parsedom_for_xbmc_plugins
Zaraz opiszę to lepiej, mam nadzieję. Może to i lepiej, że muszę podać to przystępniej. Cel: ułatwienie pracy developerom.
Pytanie pomocnicze, wiecie co to CSS i czy umiecie używać selektorów?
Coś tam o css wiem ale dawno się w to nie bawiłem...
Przykład o ile selektor może uprościć obsługę stron. Przykład z plugin.video.anime.
def Alfabetycznie():
url = 'http://animezone.pl'
r = client.request('http://animezone.pl/anime/lista')
result = client.parseDOM(r, 'div', attrs={'class': 'btn-group btn-group-xs'})
linki_litery = client.parseDOM(result, 'a', ret='href')
litery = client.parseDOM(result, 'a')
counter = 0
for link in linki_litery:
link = url + link
addon.addDir(str(litery[counter]), link, mode=3)
counter += 1
Można zamienić na (tak wiem, oczyściłem też kod):
def Alfabetycznie():
url = 'http://animezone.pl'
r = client.request(urljoin(url, '/anime/lista'))
for a in pdom.select(r, 'div.anime-list div a'):
addon.addDir(a.text, urljoin(url, a.href), mode=3)
Ten selektor można sobie przetestować na sucho wołając bibliotekę (działa z python2 jak i z python3):
git clone https://github.com/rysson/kodi-misc.git
git checkout altfix # to tylko na czas naprawy selektorów
cd kodi-misc/ParseDOM/rysson
python3 -m pdom http://animezone.pl/anime/lista 'div.anime-list div a'
Dodałem opis dla początkujących o co mniej więcej chodzi w selektorach, patrz https://github.com/rysson/kodi-misc/blob/master/ParseDOM/rysson/doc/pl/podstawy.md.
Chętnie przedyskutuję co powinienem opisać. @xulek ma rację, lepiej byłoby to omówić. Ale pewnie trudno będzie się na piwo spotkać, co?
Drugi przykład z plugin.video.anime.
def ListowanieAnime():
url = params['url']
r = client.request(url)
result2 = client.parseDOM(r, 'div', attrs={'class': 'panel-body categories-newest'}) ## na obrazy
obrazy = client.parseDOM(result2, 'img', ret='src')
result = client.parseDOM(r, 'div', attrs={'class': 'description pull-right'}) ## na linki i opisy
linki = client.parseDOM(result, 'a', ret='href')
nazwy = client.parseDOM(result, 'a')
opisy = client.parseDOM(result, 'p')
counter = 0
for link in linki:
linki[counter] = 'http://animezone.pl' + linki[counter]
obrazy[counter] = 'http://animezone.pl' + obrazy[counter]
addon.addDir(str(nazwy[counter]).replace("<mark>", "").replace("</mark>", ""), linki[counter], mode=4,
thumb=obrazy[counter], plot=opisy[counter])
counter += 1
try:
strony = client.parseDOM(r, 'ul', attrs={'class': 'pagination'})
strony = client.parseDOM(strony, 'li')
link_nastepna = client.parseDOM(strony, 'a', ret='href')[-1]
# nastepna strona
for strona in strony:
strona = client.parseDOM(strona, 'a')
if len(strona) > 0:
strona = str(strona[0])
if strona == "»":
addon.addDir("Nastpna strona..", 'http://animezone.pl' + link_nastepna, mode=3)
except:
log_exception()
pass
Nowa wersja.
def ListowanieAnime():
url = params['url'] # pomijając, że taki dostęp do atrybutów dodatku jest nie bardzo
r = client.request(url)
for a, img, desc in pdom.select(r, 'div.well.categories {{.label a, img, p}}'):
addon.addDir(a.text, urljoin(url, a.href), mode=4,
thumb=urljoin(url, img.src), plot=desc.content)
# następna strona
pages = pdom.select(r, '.pagination li a')
if pages and pages[-1].content == '»':
addon.addDir("Następna strona...", urljoin(url, pages[-1].href), mode=3)
Tutaj uwaga, użyłem {{ }}
, który chcę wywalić, bo w { }
właśnie znalazłem błąd.
A chciałbym abyście mogli to przetestować na żywo.
EDIT: Naprawiłem, { }
już działa poprawnie.
Na przykład (już bez klonowania i dla Python2):
python -m pdom http://animezone.pl/anime/lista/A 'div.well.categories {{.label a, img, p}}'
Nie wydaje się Wam, że nowa wersja jest nie tylko bardziej zwięzła ale i bardziej czytelna?
Dodałem na dobranoc możliwość wyboru, który element z zestawu nas interesuje (działa tylko w ramach zestawu { }
). Takie coś na wzór :nth-type-of dla prostych liczb.
Dajcie znać jak możemy przedyskutować te rozwiązania.
Można wybrać, które powtórzenia mają się znaleźć w wyniku.
Z przykładu wyżej selektor {p:2}
zwróci tylko opisy filmów.
Jeśli brak numeru to użyty jest zawsze o jeden większy niż poprzednio dla takiego samego selektora, czyli:
<div>
<p>Tytuł</p>
<p>Rok</p>
<a href="/gatunki">Gatunek</a>
<p>Opis</p>
<a href="/patrz">Oglądaj</a>
</div>
Z div {p, p, a:2}
daje Tytuł
(p1), Rok
(p2), Oglądaj
(a2).
Z div {p:3, p:1, p, a:2}
daje Opis
(p3), Tytuł
(p1), Rok
(p2), Oglądaj
(a2).
Z div {p:2, a, p, a, p:1}
daje Rok
(p2), Gatunek
(a1), Opis
(p3), Oglądaj
(a2), Tytuł
(p1).
Powiem Ci, że nie wiem jak to wykombinowałeś ale wygląda super :) Drastycznie zmniejsza ilość kodu
O dzięki, choć tu nie chodzi jak to zrobione, tyko jak działa.
Jak już zainteresowałem przykładem, to pytam co potrzeba, abyście poznali głębiej ideę, a właściwie bieglej się posługiwali tym wynalazkiem. Bardzo bym chciał to poprowadzić tak, aby Wam było jak najłatwiej. Mam nadzieję, że to udało mi się pokazać w przykładzie.
Co proponujecie? Ja preferuję słowo pisane, ale może przygotuję jakiś krótki filmik, wszakże zajmujemy się Kodi :-) Pokazałbym na przykładzie serwisu jak wygenerować odpowiedni kod.
Zdaję sobie sprawę, że to trochę na sucho, bo ostatnie zmiany są tutaj. Ale podstawa jest już w PTW. Do działania potrzebny jest moduł arpeggio i tu dochodzimy do ciekawej zależności. Żeby łatwo dodawać moduły (a jestem przeciwnikiem ich wrzucania bezpośrednio do kodu, przecież mamy zależności), muszę napisać kodi-repo-builder.
Projekt kodi-repo-builder rozpoczęty, ma wstępną i chaotyczną dokumentację, nawet pierwsze linijki zacząłem pisać. Umożliwi to trywialne paczkowanie dowolnego kodu, w tym zewnętrznych bibliotek. I proste składanie tego w repo. Może omawiane tutaj pdom (dawne ParseDOM) też dam jako zewnętrzną zależność, łatwiej będzie zarządzać kodem. Jeszcze zobaczymy.
Tymczasem dodałem obsługę selektora E > F (bezpośredniego dziecka), czyli w przypadku:
<div class="film">
<a href="http://film">Tytuł</a>
<div class="opis">
<a href="http://akcja">Akcja</a>
</div>
<div>
Selektor potomka div.film a
trafi w oba linki, a selektor dziecka div.film > a
tylko w jeden (ten od tytułu) bo tylko on jest bezpośrednim dzieckiem.
Na razie wystarczy. Poza dokumentacją, tutorialami itp. wstrzymam się z poprawkami do czasu, aż zgłosicie czego Wam jeszcze trzeba. No chyba, że sam natrafię w praktyce na jakąś ułomność.
Kod w repo, wszystko w masterze.
Mam problem.
Wzywam na pomoc @xulek, @notoco , @mbebe, @grzebzi, @po50on. I pozostałych, nie krępujcie się zapraszać choć trochę technicznych ludzi.
Wiem, rozpisałem się, ale proszę o zapoznanie się i komentarz. Łudzę się, że to dla dobra społeczności :-P
Niektórzy z Was pamiętają funkcję parseDOM. W tym roboczym repo jest jej udoskonalona wersja
dom.search
. I jeszcze ciekawszadom.select
.Pytanie jest o interpretację rozszerzonej funkcjonalności. Zapraszam do zapoznania się z ułomną dokumentacją. Sam próbuję dojść o co mi chodziło w lipcu :-)
Skrót rozszerzeń
Nieco poważniej, wprowadziłem coś co nazwałem „alternatywą” a właśnie przerobiłem w kodzie na „zestaw” (ang. „set”). Przyświecała mi idea ułatwienia parsowania tabelek i zestawów, np.:
Można to parsować za pomocą:
I dostaniemy:
Reklama zostanie pominięta bo nie ma
<h4>
wymaganego w zestawie.Do tego dochodzą opcje, czyli można podać np.
div.film {h4, a, p?}
, jeśli opis w<p>
może nie istnieć. Wtedy zamiastNode
dostaniemyNone
. Jest to opisane w dokumentacji.Pytanie
Selektor zestawu (dawniej alternatywy) można przecież przeplatać. Jak ma być interpretowany zestaw?
Przypadek zwykły
Opisany wyżej (typu
div.film {h4, a, p}
), tu wydaje się, że interpretacja jest rozsądna.Płaska struktura
Wyciąganie
{a,b}
może dać ciekawe efekty.<a>A1</a> <b>B1> <a>A2</a> <b>B2</b>
A1
,B1
), (A2
,B2
) ]<a>A1</a> <a>A2</a> <b>B1> <b>B2</b>
A1
,B1
), (A2
,B2
) ]<a>A1</a> <a>A2</a> <a>A3</a> <b>B1> <b>B2</b>
A1
,B1
), (A2
,B2
) ]Pierwszy wynik wydaje się OK. Drugi nieco zadziwia, ale szukamy zestawów A,B, to mamy zestawy. Trzeci może zaskoczyć, nie ma A3. Po prostu nie ma z czym stworzyć zestawu.
Czy taka interpretacja jest do przyjęcia? Jest to obecna implementacja i wynika z założeń opisanych w pierwszym przypadku (skrót rozszerzeń).
Zestaw z elementami
W zestawie może być użyty selektor, czyli możemy żądać np.
{a c, b c}
. Wyszukuje zestawu A, B (zawierających C) i z nich wybiera elementy C. I tu zaczyna się robić wesoło.<a><c>C1</c></a> <b><c>C2</c></b> <c>Cx</c>
C1
,C2
) ]<a><c>C1</c></a> <b><c>C2</c><c>C3</c></b> <c>Cx</c>
C1
,C2
) ]<b><c>C2</c><c>C3</c></b> <c>Cx</c>
W p. 2 mam duże wątpliwości. Czy powinien zwracać C2 czy C2 i C3? Teraz zwraca zestaw, a on opisuje po jednym elemencie.
Jeśli miałoby zwracać wszystkie, to trzeba zmienić upakowanie (dodatkowe zagłębienie), wtedy w 1) musi być [ ( [
C1
], [C2
] ) ], a w 2) [ ( [C1
], [C2
,C3
] ) ]. Przestaje to być czytelne i utrudnia korzystanie z pętlifor
w stylu podanym na początku.Nie wiadomo co jest intencją użytkownika tej biblioteki. Może oba warianty mają rację bytu i trzeba dodać jakiś znacznik mówiący czy chcemy wszystkie? Coś na wzór
{a c, b c*}
(czyli jeden C z A i wszystkie C z B).Zestaw i dalszy selektor
Zestaw też jest częścią innego selektora. Nie tylko przed (jak z
div.film
) ale i za nim mogą być kolejne selektory, np.{a, b} c
.Po małej dzisiejszej przeróbce (bo wylatywał wyjątek) elementy C są wyszukiwane po wybraniu zestawu, czyli wyszukuje wszystkie C z wybranego zestawu.
<a><c>C1</c></a> <b><c>C2</c></b> <c>Cx</c>
C1
], [C2
] ]<a><c>C1</c></a> <b><c>C2</c><c>C3</c></b> <c>Cx</c>
C1
], [C2
,C3
] ]Wydaje się, że taka interpretacja może być.
Apropos poprzedniego punktu. O ile
{a, b} c
jest wariantem{a c, b c}
z wszystkimi C, to generalnie nie jest to zamiennik. Nie da się zamienić{a c, b d}
.Podsumowanie
Bardo proszę o opinie i uwagi. Także o podanie przypadków, które są najbardziej przez Was pożądane. Coś, co by Wam ułatwiło życie. Także z zestawu standardowych selektorów, których obsługuję na razie znikomy podzbiór.
Ze swojego podwórka natknąłem się na problem tych samych znaczników z zestawie. Po prostu zawsze są zwracane pierwsze znalezione. Nawet jak żądamy ich wielokrotnie. Jest to zgodne z założeniem, ale upierdliwe. Np.
Żądam
div#info {p, p, p}
i dostaję...[ 'Tytuł', 'Tytuł', 'Tytuł' ]
. Może i poprawne tylko zupełnie nieprzydatne. Jak to opisać?div#info {p, p+p, p+p+p}
?div#info {p, p:nth-child(2), p:nth-child(2)}
?Pytania mnożą się jak króliki.
BTW. Ani
tag + tag
ani:nth-child
nie są jeszcze zaimplementowane.Pomocy!
EDIT: Drobiazgi w tym link do dokumentacji ~z roboczej gałęzi „altfix”~ w gałęzi master.