Problem ze scraperem

0

Witam. Jestem w trakcie robienia skryptu, który pobiera dane ze strony cnn.com. Problem polega na tym, że za każdym razem zwracana jest wartość None. Nie mogę nigdzie znaleźć solucji. Wie ktoś co mogę na to zaradzić, gdzie popełniłem błąd? Poniżej wstawię kod.

from bs4 import BeautifulSoup
import requests

source = requests.get('https://edition.cnn.com/').text
soup = BeautifulSoup(source, 'lxml')

s1 = soup.find('h2',class_="banner-text "
                              "screaming-banner-text"
                              "banner-text-size--char-47")
print(s1)
0

W odpowiedzi serwera nie ma żadnego h2. Podgląd w przeglądarce a odpowiedź serwera to 2 różne rzeczy.

0
Markuz napisał(a):

W odpowiedzi serwera nie ma żadnego h2. Podgląd w przeglądarce a odpowiedź serwera to 2 różne rzeczy.

No właśnie! I tu jeszcze rozumiem ten błąd, ale co mam zrobić aby w odpowiedzi to otrzymać? Już próbowałem na milion sposobów, utknąłem w miejscu kompletnie.

0

Tego nagłówka nie ma w pierwszym żądaniu, otwórz sobie zakładkę sieć, przejrzyj wszystkie żądania i poszukaj gdzie są wysyłane te nagłówki artykułów. Może też są w pierwszym ale trochę zakodowane, może rozbite w jakiś sposób.

Tu znalazłem: https://edition.cnn.com/data/ocs/section/index.html:intl_homepage1-zone-1/views/zones/common/zone-manager.izl

Jak to akcja jednorazowa to możesz korzystać z tego URL, jak chcesz żeby działało cały czas to będziesz musiał trochę więcej pogłówkować.

0
Markuz napisał(a):

Tego nagłówka nie ma w pierwszym żądaniu, otwórz sobie zakładkę sięć, przejrzyj wszystkie żądania i poszukaj gdzie są wysyłane te nagłówki artykułów. Może też są w pierwszym ale trochę zakodowane, może rozbite w jakiś sposób.

Tu znalazłem: https://edition.cnn.com/data/ocs/section/index.html:intl_homepage1-zone-1/views/zones/common/zone-manager.izl

Jak to akcja jednorazowa to możesz korzystać z tego URL, jak chcesz żeby działało cały czas to będziesz musiał trochę więcej pogłówkować.

Właśnie chciałbym, żeby to działało cały czas. Jest jakiś sposób aby ciągle przekierowywało mnie właśnie do takiego typu URL jak ty podesłałeś? Ogólnie idea jest taka aby kod wykonywał się na kliknięcie, a wszystko co bede chciał ze strony wyciągnąć, zapisywało się w postgresie. Ogólnie jedyne co mi stoi teraz na drodze to właśnie rozwiązanie tego problemu. Wszystko inne już mam ogarnięte i wiem co i jak, ale z czymś takim pierwszy raz się spotykam.

0

Właśnie sprawdziłem, z tym linkiem też zwraca None. Kompletnie nie mam pojęcia co zrobić, ma ktoś jakieś sugestie?

EDIT: Chyba zrobię coś takiego, że będzie mi zbierać informacje bezpośrednio przed podanie linka do artykułu.

0

Mierzyłem się ostatnio z takim samym problemem przy wyciąganiu danych z Googla za pomocą BS. Mimo wszystkich kombinacji alpejskich nic nie działało, ciągle zwracało None. Spróbowałem zrobic to samo za pomocą Selenium i działa doskonale ;).

Także, jeśli wchodzi to w grę, proponuje użyć Selenium zamiast Zupy.

2

Niestety, web scraping jest ciężki jeśli w dzisiejszych czasach JavaScript ninja. To, co widzisz w przeglądarce, wcale nie równa się temu, co dostałeś w odpowiedzi w requeście. Strona ta ściąga sobie kupę skryptów JavaScript, które następnie pobierają dynamicznie dane z zewnętrznego API i pakuje na stronie. Sam request do https://edition.cnn.com/ zwraca tylko szkielet, który będą wypełniać skrypty. Możesz to sobie sprawdzić próbując zapisać treść strony, co ją właśnie ściągłeś:

source = requests.get('https://edition.cnn.com/').text

with open('/tmp/test.html', 'w') as f:
    f.write(source.encode('utf-8'))

Chociaż nie trzeba - od tego maż developer tools i zakładkę networks. Firefox wyświetla mi pogląd tej strony, a jest ona pusta:

page.png

Skąd zatem faktyczne dane się biorą? Powiedzmy, że chcę sobie wyszukać te nagłówki "Virus" o tej epidemii w Chinach. Żeby je znaleźć, kliknąłem sobie prawym na tych requestach, wybrałem "Save as HAR', zapisałem w pliku .har (json z danymi requestów) i grepem poszukałem nagłówków - jak się okazuje lecą do API jakieś requesty pokroju https://edition.cnn.com/data/ocs/section/index.html:intl_homepage1-zone-1/views/zones/common/zone-manager.izl. Prawy klik myszy, copy as curl i można je poprać w konsoli

curl 'https://edition.cnn.com/data/ocs/section/index.html:intl_homepage1-zone-1/views/zones/common/zone-manager.izl' -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0' -H 'Accept: application/json, text/javascript, */*; q=0.01' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Referer: https://edition.cnn.com/' -H 'X-Requested-With: XMLHttpRequest' -H 'Connection: keep-alive' -H 'Cookie: FastAB=0=4293,1=7507,2=4311,3=0945,4=1431,5=2310,6=1345,7=8613,8=1408,9=2452; tryThing01=2130; ajs_user_id=null; ajs_group_id=null; ajs_anonymous_id=%2205f92a2d-c17a-404f-9a13-43b0becaa64b%22; AMCV_7FF852E2556756057F000101%40AdobeOrg=-1303530583%7CMCIDTS%7C18261%7CMCMID%7C91615181573740843924155490946665004935%7CMCAID%7CNONE%7CMCOPTOUT-1577674198s%7CNONE%7CvVersion%7C3.3.0; OptanonConsent=isIABGlobal=true&datestamp=Thu+Jan+23+2020+23%3A09%3A02+GMT%2B0100+(Central+European+Standard+Time)&version=5.11.0&landingPath=NotLandingPage&groups=req%3A1%2Csm%3A1%2Csmv%3A1%2CBG139%3A1%2Cad%3A1%2Cadv%3A1%2CBG137%3A1%2Cpf%3A1%2Cpfv%3A1%2CBG138%3A1%2Cpzv%3A1%2Cpz%3A1%2CBG140%3A1%2Cbb%3A1%2Cbbv%3A1%2CBG141%3A1%2Csa%3A1%2Csav%3A1%2CBG136%3A1&hosts=&consentId=d4affef0-f3d3-45c7-ba2f-369943c45f10&interactionCount=1&AwaitingReconsent=false&geolocation=PL%3B12; countryCode=PL; geoData=krakow|12|31-530|PL|EU|100|broadband; adobeujs-optin=%7B%22aam%22%3Afalse%2C%22adcloud%22%3Afalse%2C%22aa%22%3Atrue%2C%22campaign%22%3Afalse%2C%22ecid%22%3Atrue%2C%22livefyre%22%3Afalse%2C%22target%22%3Afalse%2C%22mediaaa%22%3Afalse%7D; seenBreakingNews=; OptanonAlertBoxClosed=2020-01-23T22:08:57.249Z; OptanonControl=ccc=PL&otvers=5.11.0&reg=gdpr&vers=1.3.3; AMCV_7FF852E2556756057F000101%40AdobeOrg=1075005958%7CMCIDTS%7C18285%7CMCMID%7C91615181573740843924155490946665004935%7CMCAID%7CNONE%7CMCOPTOUT-1579824544s%7CNONE%7CvVersion%7C4.4.1; AMCVS_7FF852E2556756057F000101%40AdobeOrg=1; cnprevpage_pn=cnn%3Ain%3Aedition%3A%2F; s_cc=true' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache' -H 'TE: Trailers'

Jak widać nasz front nam wpakował w cholerę parametrów. Jakbyśmy musieli się logować na stronie to pewnie trzeba by obsłużyć ciastka. Ale jak się okazuje większość tych parametrów jest nam do niczego potrzebna:

curl 'https://edition.cnn.com/data/ocs/section/index.html:intl_homepage1-zone-1/views/zones/common/zone-manager.izl'

Jak sobie zapisałem do pliku odpowiedź z tego endpointa, to dostałem taką stronę

page2.png

No! I to już można scrapować.

I tak wygląda właśnie scrapowanie w dzisiejszych czasach, ery ton JavaScriptu i innego dziadostwa. Jak masz szczęście, to request dla endpointu zwraca ci stary, poczciwy HTML z danymi, jakie potrzebujesz. Jak nie to trzeba znaleźć który z requestów lecących w tle zwraca dane, których potrzebujesz, często przy tym dodając odpowiednie nagłówki, zarządzając ciastkami, sesjami, identyfikatorami i innym dziadostwem, parsując JSON-y lub XML-e, czy nawet tłumacząc dane z base64, cały ten stuff które przeglądarka i skrypty robią za ciebie. Zabawa przednia, taki niby reverse erngineering strony, próba zrozumienia jak działa.

Możesz też faktycznie użyć Selenium albo Splash i wyrenderować całą stronę. Dzała to tak, że symuluje prawdziwą przeglądarkę, budując z wspomnianych JavaScriptów normalny output tak jak normalny FF czy Chrome, ale ponieważ musi to wszystko obsłużyć będzie znacznie wolniejszy. Jak chcesz mieć szybkie scrapowanie (bo na przykład zbierasz dane z dziesiątek tysięcy podstron) nie ma to sensu - trzeba wówczas patrząc w Developer Tools dowiedzieć się jakie Requesty i Response'y latają w te i wewte, po czym je ręcznie symulować.

0

Wow, genialna i wyczerpująca odpowiedź, która na prawdę wiele mi rozjaśniła bo błądziłem niesamowicie. Dzięki za poświęcony dla mnie czas. Aż zrobię sobie screena tego co napisałeś, na bank mi się przyda.

1 użytkowników online, w tym zalogowanych: 0, gości: 1