Kuinka raaputtaa Google -työpaikkoja pythonilla ja sovellusliittymillä

Google Jobs tekee ilmoituksia dynaamisesti ja lokalisoi tulokset, joten naiivit HTTP -pyynnöt palauttavat harvoin käyttökelpoiset tiedot. Luotettavin lähestymistapa on käyttää kaavintasovellusliittymää, joka käsittelee JavaScriptin renderointia ja geokohdistusta, ja jäsentä sitten vain tarvitsemasi kentät CSV: hen.

Mitä rakennat:

  • CSV -tiedostot kyselyä kohden ja sijainti työnimike, yritys, sijainti, päivämäärä, palkka, lähde ja jaa URL -osoite.
  • Skaalautuva putkilinja, joka suorittaa useita kyselyjä samanaikaisesti useiden geo-paikalla.

Menetelmä 1 - Oxylabs Web Scraper API (asynkroninen, skaalautuva)

Oxylabs 'Web Scraper API (Google Jobs -lähde) suorittaa päättömät selaimet geokohdistuksella ja mukautetulla jäsentäjällä, joten saat jäsennellyt kentät RAW HTML: n sijasta.

Mitä tarvitset

  • Oksylabs -tilin ja API -käyttäjän käyttöoikeustiedot (käyttäjänimi/salasana). Luo tili OxyLabs -kojetaulussa, aloita ilmainen kokeilu ja kopioi sovellusliittymän käyttäjä ja salasana kojelaudan käyttöoikeustieto -sivulta.
  • Python 3.11+ koneessasi.

Vaihe 1:Luo oksylabs -tili ja kopioi sovellusliittymän käyttäjänimi ja salasana kojelaudasta (oksylabs).

Vaihe 2:Asenna Python 3.11 tai uudempi järjestelmään, jos sitä ei ole vielä asennettu.

Vaihe 3:Asenna vaadittavat kirjastot Async -kaavinta varten.

pip install aiohttp asyncio pandas

Vaihe 4:Luo tiedosto nimeltäpayload.jsonGoogle -työpaikkojen (oksylabs räätälöity jäsentäjä) sääntöjen jäsenten kanssa.

{
  "source": "google",
  "url": null,
  "geo_location": null,
  "user_agent_type": "desktop",
  "render": "html",
  "parse": true,
  "parsing_instructions": {
    "jobs": {
      "_fns": [
        { "_fn": "xpath", "_args": ["//div[@class="nJXhWc"]//ul/li"] }
      ],
      "_items": {
        "job_title":     { "_fns": [{ "_fn": "xpath_one", "_args": [".//div[@class="BjJfJf PUpOsf"]/text()"] }] },
        "company_name":  { "_fns": [{ "_fn": "xpath_one", "_args": [".//div[@class="vNEEBe"]/text()"] }] },
        "location":      { "_fns": [{ "_fn": "xpath_one", "_args": [".//div[@class="Qk80Jf"][1]/text()"] }] },
        "date":          { "_fns": [{ "_fn": "xpath_one", "_args": [".//div[@class="PuiEXc"]//span[@class="LL4CDc" and contains(@aria-label, 'Posted')]/span/text()"] }] },
        "salary":        { "_fns": [{ "_fn": "xpath_one", "_args": [".//div[@class="PuiEXc"]//div[contains(@class,'I2Cbhb') and contains(@class,'bSuYSc')]//span[@aria-hidden='true']/text()"] }] },
        "posted_via":    { "_fns": [{ "_fn": "xpath_one", "_args": [".//div[@class="Qk80Jf"][2]/text()"] }] },
        "URL":           { "_fns": [{ "_fn": "xpath_one", "_args": [".//div[@data-share-url]/@data-share-url"] }] }
      }
    }
  }
}

Vaihe 5:Luo nimeltä python -tiedostojobs_oxylabs.py.

Vaihe 6:Liitä tuonti ja kuormitustiedot (oksylabs).

import asyncio
import aiohttp
import json
import pandas as pd
from aiohttp import ClientSession, BasicAuth

# Replace with your Oxylabs API username/password from the dashboard
OXY_USER = "USERNAME"
OXY_PASS = "PASSWORD"

credentials = BasicAuth(OXY_USER, OXY_PASS)

# Load parsing payload
with open("payload.json", "r") as f:
    PAYLOAD = json.load(f)

Vaihe 7:Lisää auttajatoiminnot työn, kyselyn tilan ja noutamisen tulosten (oksylabs push-pull-päätepiste) lähettämiseksi.

async def submit_job(session: ClientSession, payload: dict) -> str:
    async with session.post("https://data.oxylabs.io/v1/queries", auth=credentials, json=payload) as resp:
        data = await resp.json()
        return data["id"]

async def check_status(session: ClientSession, job_id: str) -> str:
    async with session.get(f"https://data.oxylabs.io/v1/queries/{job_id}", auth=credentials) as resp:
        data = await resp.json()
        return data["status"]

async def fetch_jobs(session: ClientSession, job_id: str) -> list:
    async with session.get(f"https://data.oxylabs.io/v1/queries/{job_id}/results", auth=credentials) as resp:
        data = await resp.json()
        return data["results"][0]["content"]["jobs"]

Vaihe 8:Lisää toiminto jäsennettyjen työpaikkojen kirjoittamiseen CSV: hen kyselyä kohti ja sijainti.

Liittyvät:Kuinka ajaa python -skripti Dockerin avulla

async def save_csv(query: str, location: str, jobs: list) -> None:
    rows = []
    for j in jobs:
        rows.append({
            "Job title": j.get("job_title"),
            "Company name": j.get("company_name"),
            "Location": j.get("location"),
            "Date": j.get("date"),
            "Salary": j.get("salary"),
            "Posted via": j.get("posted_via"),
            "URL": j.get("URL"),
        })
    df = pd.DataFrame(rows)
    filename = f"{query}_jobs_{location.replace(',', '_').replace(' ', '_')}.csv"
    await asyncio.to_thread(df.to_csv, filename, index=False)

Vaihe 9:Määritä Coroutiini, joka asettaa Google Jobsin URL-osoitteen ja maantieteellisen sijainnin, toimittaa työn, odottaa valmistumista ja säästää tuloksia (oksylabs).

async def scrape_jobs(session: ClientSession, query: str, country_code: str, location: str) -> None:
    url = f"https://www.google.com/search?q={query}&ibp=htl;jobs&hl=en&gl={country_code}"
    PAYLOAD["url"] = url
    PAYLOAD["geo_location"] = location

    job_id = await submit_job(session, PAYLOAD)

    # Give the backend time to render before polling
    await asyncio.sleep(12)

    while True:
        status = await check_status(session, job_id)
        if status == "done":
            break
        if status == "failed":
            print(f"Job {job_id} failed for {query} @ {location}.")
            return
        await asyncio.sleep(5)

    jobs = await fetch_jobs(session, job_id)
    await save_csv(query, location, jobs)

Vaihe 10:Lisätämain()suorittaa useita kyselyjä ja sijainteja samanaikaisesti.

URL_QUERIES = ["developer", "chef", "manager"]
LOCATIONS = {
    "US": ["California,United States", "Virginia,United States", "New York,United States"],
    "GB": ["United Kingdom"],
    "DE": ["Germany"]
}

async def main():
    async with aiohttp.ClientSession() as session:
        tasks = []
        for cc, locs in LOCATIONS.items():
            for loc in locs:
                for q in URL_QUERIES:
                    tasks.append(asyncio.ensure_future(scrape_jobs(session, q, cc, loc)))
        await asyncio.gather(*tasks)

if __name__ == "__main__":
    asyncio.run(main())
    print("Completed.")

Vaihe 11:Suorita komentosarja ja tarkista, että CSV -tiedostot luodaan kyselyä ja sijaintia kohti.

Huomautuksia:

  • Google Jobs Ostral URL -osoitteet voivat avata vain IP: stä samassa maassa, jota käytetään kaavin aikana; Käytä vastaavaa välityspalvelinta/VPN: tä avaamalla ne.
  • KäyttääCtrl+Shift+IWindowsissa taiOption+Command+IMacOS: lla tarkastaa valintalaitteet, jos haluat laajentaa jäsentämistä.

Menetelmä 2 - Serpapi Google Jobs API (yksinkertainen lepo, suodattimet ja säde)

Serpapigoogle_jobsMoottorin palauttaa jäsennellyt ilmoitukset valinnaisilla suodattimilla, kuten kieli, maa ja säde.

Mitä tarvitset

  • Serpapi -tili ja API -avain. Rekisteröidy osoitteeseen serpapi.com, avaa kojelauta ja kopioi sovellusliittymän avain “API -avain” -sivulta.
  • Python 3.9+ jarequestsjapandaspaketit.

Vaihe 1:Luo SerPAPI -tili ja kopioi sovellusliittymän avain kojelaudasta (SerPAPI).

Vaihe 2:Asenna riippuvuudet.

pip install requests pandas

Vaihe 3:Lähetä ensimmäinen Google Jobs -pyyntösi ja kirjoita tulokset CSV: lle (SerPAPI).

import requests
import pandas as pd

API_KEY = "YOUR_SERPAPI_KEY"

params = {
    "engine": "google_jobs",
    "q": "developer new york",
    "hl": "en",
    "gl": "us",
    "api_key": API_KEY,
    # Optional: radius in kilometers (Google may not strictly enforce)
    "lrad": 25
}

r = requests.get("https://serpapi.com/search.json", params=params)
r.raise_for_status()
data = r.json()

rows = []
for j in data.get("jobs_results", []):
    rows.append({
        "Job title": j.get("title"),
        "Company name": j.get("company_name"),
        "Location": j.get("location"),
        "Posted via": j.get("via"),
        "Share link": j.get("share_link"),
        "Description": j.get("description")
    })

pd.DataFrame(rows).to_csv("jobs_serpapi.csv", index=False)

Vaihe 4:Sivuta käyttämällänext_page_tokenVastauksesta ylimääräisten sivujen hakemiseen (serpapi).

def fetch_all(params):
    out = []
    while True:
        res = requests.get("https://serpapi.com/search.json", params=params).json()
        out.extend(res.get("jobs_results", []))
        token = res.get("serpapi_pagination", {}).get("next_page_token")
        if not token:
            break
        params["next_page_token"] = token
    return out

jobs = fetch_all(params)

Vinkit:

  • Käyttäälocationtaiuulesimuloida kaupunkitason hakuja; Vältä yhdistämällä molemmat samassa pyynnössä.
  • Suodattimet voivat saapuaudsjouset JSON: ssa; Käytä suodattimen uudelleenudsarvo uudessa tulosten tarkentamispyynnössä.

Menetelmä 3 - Ilmainen paikallinen kaavin seleenillä (paras pienille testeille)

Päättömä selain voi vierittää Google Jobs -luetteloa ja purkaa kentät vankilla valintalaitteilla. Tämä on käytännöllinen prototyyppien suhteen, mutta vaatii ylläpitoa ja voi lyödä anti-bot-järjestelmiä tilavuudella.

Mitä tarvitset

  • Google Chrome ja vastaava Chromedriver binaarinen.
  • Python 3.9+selenium-beautifulsoup4(valinnainen) japandas.

Vaihe 1:Lataa Chromedriver, joka vastaa Chrome -versiota ja lisää sen polullesi.

Vaihe 2:Asenna seleeni ja pandat.

pip install selenium pandas

Vaihe 3:Käynnistä Chrome vaihtoehto, joka vähentää automaation sormenjälkiä.

from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument("--window-size=1920,1080")
options.add_argument("--disable-blink-features=AutomationControlled")

driver = webdriver.Chrome(options=options)

Vaihe 4:Avaa kyselystä ja maakoodista rakennetun Google Jobs -URL -osoitteen.

query = "developer"
country = "us"
url = f"https://www.google.com/search?q={query}&ibp=htl;jobs&hl=en&gl={country}"
driver.get(url)

Vaihe 5:Vieritä työluettelon säilöä ladataksesi lisää tuloksia.

import time
from selenium.webdriver.common.by import By

loaded = 0
while True:
    cards = driver.find_elements(By.XPATH, "//div[@class="nJXhWc"]//ul/li")
    if len(cards) == loaded:
        break
    loaded = len(cards)
    driver.execute_script("arguments[0].scrollIntoView({block: 'end'});", cards[-1])
    time.sleep(1.5)

Vaihe 6:Uuteta vakaa kentät XPathilla; Käytä kuvakepohjaisia ​​valittajia lähetettyyn päivämäärään ja palkkaan, kun ne ovat saatavilla.

from selenium.common.exceptions import NoSuchElementException

rows = []
for li in driver.find_elements(By.XPATH, "//div[@class="nJXhWc"]//ul/li//div[@role="treeitem"]/div/div"):
    def txt(xp):
        try:
            return li.find_element(By.XPATH, xp).get_attribute("innerText")
        except NoSuchElementException:
            return None

    def attr(xp, name):
        try:
            return li.find_element(By.XPATH, xp).get_attribute(name)
        except NoSuchElementException:
            return None

    rows.append({
        "Job title": txt("./div[2]"),
        "Company name": txt("./div[4]/div/div[1]"),
        "Location": txt("./div[4]/div/div[2]"),
        "Source": txt("./div[4]/div/div[3]"),
        "Posted": txt(".//*[name()='path'][contains(@d,'M11.99')]/ancestor::div[1]"),
        "Full/Part": txt(".//*[name()='path'][contains(@d,'M20 6')]/ancestor::div[1]"),
        "Salary": txt(".//*[name()='path'][@fill-rule="evenodd"]/ancestor::div[1]"),
        "Logo src": attr("./div[1]//img", "src")
    })

Vaihe 7:Tallenna poimitut tiedot CSV: ksi.

import pandas as pd
pd.DataFrame(rows).to_csv("jobs_selenium.csv", index=False)

VAROITUS:

  • Odottaa asettelun muutoksia; Revalidoi valittajia määräajoin.
  • Kaasupyynnöt ja kunnioittavat sivuston ehtoja lohkojen välttämiseksi.

Lähestymistavan valitseminen

Tuotantoa ja mittakaavaa varten Oxylabsin Async -putkilinja palauttaa luotettavasti jäsennettyjä työpaikkoja monien kyselyjen ja paikkojen välillä vähentäen tekniikan aikaa ja vikoja. Serpapi integroidaan nopeasti pienempiin skripteihin ja antaa sinun lisätä säde- ja suodatinmerkkejä. Seleeni on paras nopeisiin kokeisiin tai kun et voi käyttää kolmannen osapuolen sovellusliittymää.

Nopea ylläpitovinkki: Pidä kyselyluetteloita ja sijaintiansanoja erillisissä JSON- tai YAML-tiedostoissa, jotta muut kuin kehittäjät voivat päivittää hakualueita koskettamatta koodia.

Related Posts