Vinnaren i pepparkakshustävlingen!
2022-04-19, 13:37
  #1
Medlem
Bonnatorps avatar
Tänkte starta det här som en hjälptråd för mitt lilla hobbyprojekt för att samla nummer från Eniro.
Ja det är antagligen emot användarvillkoren att göra digitala kopior av datan över huvud taget, men jag gör ändå samma sak manuellt för att samla in numren och skulle vilja spara lite tid.

Som jag uppfattar det så ska jag använda openpyxl för att läsa från och skriva till excelfiler.
Just den biten har jag inte kommit igång med än, men det är nästa steg så fort jag fått pli på själva webscrapingen.

För scrapingen i fråga uppfattar jag det som att Selenium är det som ska bära bördan.
Jag har skummat igenom Python Automation Cookbook, och antar att följande är ett lämpligt kodstycke för att bara skriva in ett namn i sökrutan:
Kod:
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.eniro.se/')
time.sleep(5)
search = browser.find_elements_by_name("searchQuery")
search.send_keys("Sven Svensson")
Sleepen är för att jag ska hinna godkänna cookies, har inte hittat elementet för den knappen.
Inputelementet, som jag antar motsvarar sökrutan, har namnet "searchQuery".
Men ingen text skrivs in, och ingen sökning görs. Det ser ut som att chromesidan som öppnas interagerar med sökknappen då den markeras för en ytterst kort stund, men som sagt så har inget namn skrivits in och inget händer.

Vad missar jag?
__________________
Senast redigerad av Bonnatorp 2022-04-19 kl. 13:41.
Citera
2022-04-19, 13:46
  #2
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av Bonnatorp
Tänkte starta det här som en hjälptråd för mitt lilla hobbyprojekt för att samla nummer från Eniro.
Ja det är antagligen emot användarvillkoren att göra digitala kopior av datan över huvud taget, men jag gör ändå samma sak manuellt för att samla in numren och skulle vilja spara lite tid.

Som jag uppfattar det så ska jag använda openpyxl för att läsa från och skriva till excelfiler.
Just den biten har jag inte kommit igång med än, men det är nästa steg så fort jag fått pli på själva webscrapingen.

För scrapingen i fråga uppfattar jag det som att Selenium är det som ska bära bördan.
Jag har skummat igenom Python Automation Cookbook, och antar att följande är ett lämpligt kodstycke för att bara skriva in ett namn i sökrutan:
Kod:
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.eniro.se/')
time.sleep(5)
search = browser.find_elements_by_name("searchQuery")
search.send_keys("Sven Svensson")
Sleepen är för att jag ska hinna godkänna cookies, har inte hittat elementet för den knappen.
Inputelementet, som jag antar motsvarar sökrutan, har namnet "searchQuery".
Men ingen text skrivs in, och ingen sökning görs. Det ser ut som att chromesidan som öppnas interagerar med sökknappen då den markeras för en ytterst kort stund, men som sagt så har inget namn skrivits in och inget händer.

Vad missar jag?
Låt mig ifrågasätta en grundpremiss:
Selenium vill du enbart använda om du måste, eftersom det är långsamt och fippligt.
Om du istället använder hitta.se som källa så kan du istället använda ett enkelt curl-anrop.
Kod:
curl https://www.hitta.se/s%C3%B6k?vad=sven%20svensson
Det här är alltså direkt i terminalen, men genom requests-modulen kan du läsa in HTML-koden från sidan i en variabel, oerhört mycket snabbare och enklare än genom Selenium. Du behöver omvandla ditt söknamn "Sven Svensson" till en URL-kod.

Du kan sedan använda t.ex. Beautiful Soup för att "parsa" HTML-koden som Curl-anropet presterar.

Edit: Du kan eventuellt få till samma resultat med Eniro om du gräver lite i hur den sidan är uppbyggd, ett försök nedan som funkar i min browser (men inte i curl), kanske beror på session_id eller liknande cookie:
Kod:
https://www.eniro.se/api/cs?device=desktop&query=sven%20svensson&sortOrder=default&profile=se&page=1&lat=0&lng=0&limit=25&review=0&webshop=false&client=true
__________________
Senast redigerad av Enterprise 2022-04-19 kl. 13:58.
Citera
2022-04-19, 14:02
  #3
Medlem
JohannesSnajdares avatar
Håller helt med Enterprise, gå direkt på källan och undvik in i det längsta att försöka automatisera webbläsaren.

Sen kommer Eniro & Hitta förmodligen blocka dig rätt fort om du börjar hamra på för hårt, lägg in en liten delay mellan anropen så kanske du klarar dig. Eller sprid ut jobbet på en massa (ovetandes?) bottar som sedan submittar in resultaten till dig där du samlar ihop det.
Citera
2022-04-19, 14:09
  #4
Medlem
Bonnatorps avatar
Citat:
Ursprungligen postat av Enterprise
Låt mig ifrågasätta en grundpremiss:
Selenium vill du enbart använda om du måste, eftersom det är långsamt och fippligt.
Om du istället använder hitta.se som källa så kan du istället använda ett enkelt curl-anrop.
Kod:
curl https://www.hitta.se/s%C3%B6k?vad=sven%20svensson
Det här är alltså direkt i terminalen, men genom requests-modulen kan du läsa in HTML-koden från sidan i en variabel, oerhört mycket snabbare och enklare än genom Selenium. Du behöver omvandla ditt söknamn "Sven Svensson" till en URL-kod.

Du kan sedan använda t.ex. Beautiful Soup för att "parsa" HTML-koden som Curl-anropet presterar.

Edit: Du kan eventuellt få till samma resultat med Eniro om du gräver lite i hur den sidan är uppbyggd, ett försök nedan som funkar i min browser (men inte i curl), kanske beror på session_id eller liknande cookie:
Kod:
https://www.eniro.se/api/cs?device=desktop&query=sven%20svensson&sortOrder=default&profile=se&page=1&lat=0&lng=0&limit=25&review=0&webshop=false&client=true
Okej, så att anropa ren URL istället, samt använda bara Beautifulsoup för parsingen är ett bättre alternativ?

Citat:
Ursprungligen postat av JohannesSnajdare
Håller helt med Enterprise, gå direkt på källan och undvik in i det längsta att försöka automatisera webbläsaren.

Sen kommer Eniro & Hitta förmodligen blocka dig rätt fort om du börjar hamra på för hårt, lägg in en liten delay mellan anropen så kanske du klarar dig. Eller sprid ut jobbet på en massa (ovetandes?) bottar som sedan submittar in resultaten till dig där du samlar ihop det.
Jo jag tänkte lägga in lite random sleeptimers här och var.
Det gör inget om det går lika sakta att göra det automatiserat som för hand, bara man faktiskt slipper göra arbetet i fråga.
Citera
2022-04-19, 14:10
  #5
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av Bonnatorp
Okej, så att anropa ren URL istället, samt använda bara Beautifulsoup för parsingen är ett bättre alternativ?
Japp, börja så och kolla hur det går.
Citera
2022-04-19, 14:15
  #6
Medlem
Enklast att använda deras api direkt.

Kod:
response = requests.get(https://www.eniro.se/api/ps?query=Sven+Svensson+stockholm&sortOrder=default)

Är antagligen inte tillåtet men använd delay + vpn så borde det inte vara några problem.
Citera
2022-04-19, 14:38
  #7
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av zizty
Enklast att använda deras api direkt.

Kod:
response = requests.get(https://www.eniro.se/api/ps?query=Sven+Svensson+stockholm&sortOrder=default)

Är antagligen inte tillåtet men använd delay + vpn så borde det inte vara några problem.
Ja, det där var ju ännu bättre, då får man svaret i ren JSON som är enkelt att omvandla till ett objekt. 👍
Citera
2022-04-20, 21:21
  #8
Medlem
Bonnatorps avatar
Det går sakta men säkert framåt.

Nu stöter jag på ett annat problem, jag har följande kod hittills:
Kod:
# -*- coding: iso-8859-1 -*-
# -*- coding: latin-1 -*-
import time
import requests
from bs4 import BeautifulSoup
from selenium import webdriver

first = "Sven"
last = "Svensson"
street = "Storgatan"
streetnumber = "1"
browser = webdriver.Chrome()
browser.get('https://www.eniro.se/' + first + '+' + last + '+' + street + '+' + streetnumber + '/personer')
time.sleep(5)
btn = driver.find_element_by_class("hero-lead-icon__icon-container--inverted phoneNumber");
btn.click();
Har klippt bort lite annan kod, minns inte vilka av modulerna ovan jag faktiskt använder i detta kodstycke, men någon av dem är det.
Eftersom varje person har ett ID som jag inte har tillgång till utan att faktiskt gå in på länken tänkte jag att det blir enklast att använda Selenium ändå och göra sökningen med en direkt-url (antagligen lägga till postnummer också för bättre noggrannhet), öppna den första personen som dyker upp i listan och därefter hämta nummerlistan som dyker upp längst ner i popupen.
Det gör inget om det är lite slött då jag gissningsvis kommer ha en del sleeptimers ändå, tänkte inte hamra in 20.000 nummer på en halvtimme.

Men jag får felmeddelande på näst sista raden, att "NameError: name 'driver' is not defined. Did you mean: 'webdriver'.
Är inte det en seleniummetod som torde fungera rakt av?

Citat:
Ursprungligen postat av zizty
Enklast att använda deras api direkt.

Kod:
response = requests.get(https://www.eniro.se/api/ps?query=Sven+Svensson+stockholm&sortOrder=default)

Är antagligen inte tillåtet men använd delay + vpn så borde det inte vara några problem.

Citat:
Ursprungligen postat av Enterprise
Ja, det där var ju ännu bättre, då får man svaret i ren JSON som är enkelt att omvandla till ett objekt. 👍
Tänkte att det skulle vara omständigt att lära sig JSON också, men det var ju mycket simplare än vad jag antog.
Utmärkt lösning!

Då får jag alltså ett felmeddelande på det istället:
Kod:
response = requests.get('https://www.eniro.se/api/ps?query=sven+svensson+stockholm&sortOrder=default')
time.sleep(3)
data = response.json()
print (data["phoneNumber"])
Får en KeyError på att phoneNumbers inte finns, fastän den syns tydligt i listan som dyker upp om jag går in på länken manuellt.
Vad kan vara felet?
__________________
Senast redigerad av Bonnatorp 2022-04-20 kl. 22:17.
Citera
2022-04-20, 22:20
  #9
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av Bonnatorp
Då får jag alltså ett felmeddelande på det istället:
Kod:
response = requests.get('https://www.eniro.se/api/ps?query=sven+svensson+stockholm&sortOrder=default')
time.sleep(3)
data = response.json()
print (data["phoneNumber"])
Får en KeyError på att phoneNumbers inte finns, fastän den syns tydligt i listan som dyker upp om jag går in på länken manuellt.
Vad kan vara felet?
Nja, du har inte kollat på objektet tillräckligt noga.
data är en Dict som har en array under sig som heter "items" med massor av dicts under sig (alltså själva de hittade personerna), dessa dicts har bl.a. nyckeln "phonenumbers" (den du letar efter)
Kolla data["items"] och ta det därifrån.
Citera
2022-04-20, 22:54
  #10
Medlem
Bonnatorps avatar
Citat:
Ursprungligen postat av Enterprise
Nja, du har inte kollat på objektet tillräckligt noga.
data är en Dict som har en array under sig som heter "items" med massor av dicts under sig (alltså själva de hittade personerna), dessa dicts har bl.a. nyckeln "phonenumbers" (den du letar efter)
Kolla data["items"] och ta det därifrån.
Hur gör jag för att ladda dicten phoneNumbers inuti items?
Måste jag köra en json.loads() igen och stacka sådana tills jag är på phoneNumber?
Citera
2022-04-20, 22:59
  #11
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av Bonnatorp
Hur gör jag för att ladda dicten phoneNumbers inuti items?
Måste jag köra en json.loads() igen och stacka sådana tills jag är på phoneNumber?
Nej, det finns redan där
Det är alltså "nestade" objekt (dicts och arrays) som packats upp ur JSON-filen.

prova t.ex:
Kod:
print(data["items"][0]["phoneNumbers"]) 

För att få det första numret i item 0:
Kod:
print(data["items"][0]["phoneNumbers"][0]["phoneNumber"]) 
__________________
Senast redigerad av Enterprise 2022-04-20 kl. 23:02.
Citera
2022-04-20, 23:26
  #12
Medlem
EastAreaPapists avatar
Citat:
Ursprungligen postat av Bonnatorp
Hur gör jag för att ladda dicten phoneNumbers inuti items?
Måste jag köra en json.loads() igen och stacka sådana tills jag är på phoneNumber?
Det är oftast smidigare att jobba med en dataframe. Du kan expandera listan med telefonnummer med explode och skriva till en excel-fil med to_excel.
Kod:
import pandas as pd

# read data
df = pd.DataFrame(data['items'])
# expand phoneNumbers (1 per row)
df = df.explode('phoneNumbers')
# write to excel
df[['id', 'name', 'phoneNumbers']].to_excel('telefon_nummer.xlsx')
Citera

Stöd Flashback

Flashback finansieras genom donationer från våra medlemmar och besökare. Det är med hjälp av dig vi kan fortsätta erbjuda en fri samhällsdebatt. Tack för ditt stöd!

Stöd Flashback