SHOW:
|
|
- or go back to the newest paste.
| 1 | ## for https://stackoverflow.com/q/75031138/6146136 | |
| 2 | - | ## based on https://stackoverflow.com/a/75032654/6146136 |
| 2 | + | |
| 3 | ||
| 4 | from selenium import webdriver | |
| 5 | - | import requests |
| 5 | + | from selenium.webdriver.common.by import By |
| 6 | from selenium.webdriver.support.ui import WebDriverWait | |
| 7 | from selenium.webdriver.support import expected_conditions as EC | |
| 8 | ||
| 9 | from urllib.parse import urljoin | |
| 10 | from bs4 import BeautifulSoup | |
| 11 | import pandas as pd ## only needed for saving as csv | |
| 12 | import os ## only needed for printing csv path at end | |
| 13 | ||
| 14 | ########################################################################### | |
| 15 | - | maxPages = 70 # [there should be only 53, but just in case] |
| 15 | + | |
| 16 | - | csv_path = 'asda_jobs__requests.csv' # path to csv file to save to |
| 16 | + | |
| 17 | ||
| 18 | maxPages = 50 # there's only 25 but there will be duplicates | |
| 19 | - | url = "https://www.asda.jobs/vacancy/find/results/ajaxaction/posbrowser_gridhandler/?" |
| 19 | + | max_wait = 1 # 5 ## 30 ## as you need |
| 20 | - | s = requests.Session() |
| 20 | + | csv_path = 'asda_jobs.csv' # path to csv file to save to |
| 21 | - | s.get("https://www.asda.jobs/vacancy/find/results/")
|
| 21 | + | |
| 22 | - | pagestamp = s.cookies['earcusession'][5:-8] |
| 22 | + | |
| 23 | - | url = url + f"pagestamp={pagestamp}"
|
| 23 | + | btn_sel = "a.scroller_movenext" # .buttonEnabled" |
| 24 | url = "https://www.asda.jobs/vacancy/find/results/" | |
| 25 | ecv = EC.visibility_of_all_elements_located | |
| 26 | - | for pgi in range(maxPages): |
| 26 | + | |
| 27 | - | page = s.get(url+f"&movejump={pgi}&movejump_page={pgi+1}")
|
| 27 | + | options = webdriver.ChromeOptions() |
| 28 | - | if page.status_code != 200: break |
| 28 | + | options.add_argument('--headless')
|
| 29 | - | soup = BeautifulSoup(page.content, "lxml") |
| 29 | + | browser = webdriver.Chrome(chrome_options=options) |
| 30 | wait = WebDriverWait(browser, max_wait).until | |
| 31 | browser.get(url) | |
| 32 | ||
| 33 | addedRows, listings = [], [] | |
| 34 | for pgi in range(maxPages): | |
| 35 | wait(ecv((By.CSS_SELECTOR, row_sel))) | |
| 36 | ||
| 37 | soup = BeautifulSoup(browser.page_source, 'html5lib') | |
| 38 | pgListing = [selectForList(rowSoup, {
| |
| 39 | 'pageNum': (pgi+1, '"staticVal"'), | |
| 40 | - | if not pgl['link']: continue |
| 40 | + | |
| 41 | 'jobRef': ('UNKNOWN', '"staticVal"'),
| |
| 42 | 'title': ('a[title]', 'title'),
| |
| 43 | 'about': 'div.rowContentContainer', | |
| 44 | 'link': ('a[href]', 'href')
| |
| 45 | - | if jobRef: pgListing[li]['jobRef'] = jobRef[-1] |
| 45 | + | |
| 46 | - | |
| 46 | + | |
| 47 | - | newCt = len(set([l['rowId'] for l in pgListing if l['rowId'] and l['rowId'] not in addedRows])) |
| 47 | + | if not pgl['link']: |
| 48 | - | print(page.status_code, page.reason, 'scraped', newCt, 'new from ', end='') |
| 48 | + | continue |
| 49 | - | selectForList(soup, ['div.pagingText', 'span.filtersSummaryTextInnerContainer'], printList=' : ') |
| 49 | + | |
| 50 | - | if not newCt: break |
| 50 | + | |
| 51 | jobRef = lLink.split('/vacancy/', 1)[-1].split('/')[0]
| |
| 52 | - | # listings += pgListing # allows duplicates [probably fine in THIS method] |
| 52 | + | |
| 53 | - | listings += [l for l in pgListing if not (l['rowId'] and l['rowId'] in addedRows)] |
| 53 | + | if jobRef: |
| 54 | - | addedRows += [l['rowId'] for l in pgListing] |
| 54 | + | pgListing[li]['jobRef'] = jobRef[-1] |
| 55 | newCt = len(set([ | |
| 56 | l['rowId'] for l in pgListing if l['rowId'] | |
| 57 | and l['rowId'] not in addedRows])) | |
| 58 | print(f'{str([pgi]):>5}', 'scraped', newCt, 'new from ', end='')
| |
| 59 | selectForList(soup, [ | |
| 60 | 'div.pagingText', 'span.filtersSummaryTextInnerContainer' | |
| 61 | ], printList=' : ') | |
| 62 | ||
| 63 | - | ]), f'\n\nsaved {len(listings)} to "{os.path.abspath(csv_path)}"') |
| 63 | + | # listings += pgListing # allows duplicates |
| 64 | listings += [l for l in pgListing if not ( | |
| 65 | l['rowId'] and l['rowId'] in addedRows)] | |
| 66 | addedRows += [l['rowId'] for l in pgListing] | |
| 67 | ||
| 68 | nextBtn = browser.find_elements(By.CSS_SELECTOR, btn_sel) | |
| 69 | if nextBtn: | |
| 70 | browser.execute_script( | |
| 71 | "arguments[0].scrollIntoView(false);", nextBtn[-1]) | |
| 72 | try: | |
| 73 | nextBtn[-1].click() | |
| 74 | except: | |
| 75 | nextBtn[-1].click() | |
| 76 | else: | |
| 77 | break | |
| 78 | ||
| 79 | browser.quit() | |
| 80 | del browser | |
| 81 | ||
| 82 | pd.DataFrame(listings).to_csv(csv_path, index=False) | |
| 83 | ||
| 84 | print('\n\nRemoved 1 duplicate each for rows with ID\n', ', '.join(
| |
| 85 | f'{ri}' for ri in set(addedRows) if addedRows.count(ri) == 2
| |
| 86 | ), '\nOther repeated rows:\n\t', '\n\t '.join([ | |
| 87 | f'rowID_{ri} : skipped {addedRows.count(ri)-1} duplicates'
| |
| 88 | for ri in set(addedRows) if addedRows.count(ri) > 2 | |
| 89 | ]), f'\n\nsaved {len(listings)} to "{os.path.abspath(csv_path)}"')
| |
| 90 |