warn-scraper 1.2.158.dev0__py3-none-any.whl → 1.2.159.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
warn/scrapers/fl.py CHANGED
@@ -9,6 +9,7 @@ import requests
9
9
  import tenacity
10
10
  import urllib3
11
11
  from bs4 import BeautifulSoup
12
+ from pyquery import PyQuery as pq
12
13
 
13
14
  from .. import utils
14
15
  from ..cache import Cache
@@ -17,7 +18,8 @@ __authors__ = ["zstumgoren", "Dilcia19", "shallotly", "stucka"]
17
18
  __tags__ = ["html", "pdf"]
18
19
  __source__ = {
19
20
  "name": "Florida Department of Economic Opportunity",
20
- "url": "https://floridajobs.org/office-directory/division-of-workforce-services/workforce-programs/reemployment-and-emergency-assistance-coordination-team-react/warn-notices",
21
+ # "url": "https://floridajobs.org/office-directory/division-of-workforce-services/workforce-programs/reemployment-and-emergency-assistance-coordination-team-react/warn-notices",
22
+ "url": "https://floridajobs.org/workforce-resources/worker-adjustment-and-retraining-notification-(warn)",
21
23
  }
22
24
 
23
25
  logger = logging.getLogger(__name__)
@@ -53,25 +55,24 @@ def scrape(
53
55
  headers = {
54
56
  "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36"
55
57
  }
56
- url = "https://floridajobs.org/office-directory/division-of-workforce-services/workforce-programs/reemployment-and-emergency-assistance-coordination-team-react/warn-notices"
58
+ # url = "https://floridajobs.org/office-directory/division-of-workforce-services/workforce-programs/reemployment-and-emergency-assistance-coordination-team-react/warn-notices"
59
+ url = "https://floridajobs.org/workforce-resources/worker-adjustment-and-retraining-notification-(warn)"
57
60
  response = requests.get(url, headers=headers, verify=True)
58
61
  logger.debug(f"Request status is {response.status_code} for {url}")
59
- soup = BeautifulSoup(response.text, "html.parser")
60
- pageholder = soup.select("div.mainContentArea")[0]
61
- pagesection = pageholder.select("div.sfContentBlock")[0]
62
+ html = response.text
63
+ details = pq(html)("div.contact-details")
62
64
  href_lookup = {}
63
- for atag in pagesection.find_all("a"):
64
- href = atag["href"]
65
+ for link in pq(details)("a.externalIcon"):
66
+ # logger.debug(pq(link))
67
+ href = pq(link)("a").attr("href")
65
68
  tagyear = href[-4:]
66
- if tagyear not in ["orts"]:
69
+ if tagyear not in ["orts"]: # exclude "reports"
67
70
  href_lookup[tagyear] = href
68
71
 
69
- # logger.debug(href_lookup)
70
- # logger.debug(pagesection)
71
-
72
72
  base_url = "https://reactwarn.floridajobs.org/WarnList/"
73
73
 
74
74
  # Loop through years and add any missing to the lookup
75
+ # logger.debug(href_lookup.keys())
75
76
  most_recent_year = int(list(href_lookup.keys())[0])
76
77
  earliest_year = 2015 # We expected files to be available for at least 2015
77
78
  for year in range(earliest_year, most_recent_year):
warn/scrapers/oh.py CHANGED
@@ -1,12 +1,13 @@
1
1
  import csv
2
- import json
3
2
  import logging
3
+ import re
4
+ from io import StringIO
4
5
  from pathlib import Path
5
6
 
6
7
  import requests
7
- from bs4 import BeautifulSoup, Tag
8
8
 
9
9
  from .. import utils
10
+ from ..cache import Cache
10
11
 
11
12
  __authors__ = ["zstumgoren", "Dilcia19", "chriszs", "stucka"]
12
13
  __tags__ = ["html", "pdf"]
@@ -32,6 +33,7 @@ def scrape(
32
33
  Returns: the Path where the file is written
33
34
  """
34
35
  state_code = "oh"
36
+ cache = Cache()
35
37
 
36
38
  # Get the latest HTML
37
39
  headers = {
@@ -39,29 +41,26 @@ def scrape(
39
41
  }
40
42
 
41
43
  # latesturl = "https://jfs.ohio.gov/wps/portal/gov/jfs/job-services-and-unemployment/job-services/job-programs-and-services/submit-a-warn-notice/current-public-notices-of-layoffs-and-closures-sa/current-public-notices-of-layoffs-and-closures"
42
- latesturl = "https://jfs.ohio.gov/job-services-and-unemployment/job-services/job-programs-and-services/submit-a-warn-notice/current-public-notices-of-layoffs-and-closures-sa"
43
-
44
+ # latesturl = "https://jfs.ohio.gov/job-services-and-unemployment/job-services/job-programs-and-services/submit-a-warn-notice/current-public-notices-of-layoffs-and-closures-sa"
45
+ latesturl = "https://jfs.ohio.gov/job-workforce-services/job-programs-and-services/submit-a-warn-notice/current-public-notices-of-layoffs-and-closures"
44
46
  logger.debug(f"Attempting to fetch current data from {latesturl}")
45
47
  r = requests.get(latesturl, headers=headers)
46
- soup = BeautifulSoup(r.content, features="lxml")
47
- logger.debug("Attempting to get JSON data from Ohio file")
48
- data_div = soup.find("div", {"id": "js-placeholder-json-data"})
49
- if isinstance(data_div, Tag):
50
- data = json.loads(data_div.decode_contents().strip())["data"]
51
- else:
52
- logger.debug("!!!!!!!!!!!!!!!!!!!! Could not find JSON data div")
53
- logger.debug(soup)
54
- raise ValueError("Could not find JSON data div")
55
- rawheaders = data[1]
56
- logger.debug(f"Found headers: {rawheaders}")
57
- masterlist = []
58
- for row in data[2:]:
59
- if len(row) == len(rawheaders):
60
- line = {}
61
- for i, item in enumerate(rawheaders):
62
- if item != "":
63
- line[item] = row[i]
64
- masterlist.append(line)
48
+ cache.write("oh/index.html", r.text)
49
+ logger.debug("Attempting to get CSV link from Ohio file")
50
+ html = r.text
51
+ csv_url = re.findall(r"(\\\"csvUrl\\\":\\\")(.*?)(\\\")", html)[0][1]
52
+ logger.debug(f"CSV link found at {csv_url}")
53
+ r = requests.get(csv_url, headers=headers)
54
+ cache.write("oh/rawdata.csv", r.text)
55
+
56
+ # Ohio CSV as of June 2026 was coming in with extra prefacing headers that ... make it not a CSV.
57
+ # So knock off any lines without useful data.
58
+ clean = []
59
+ for myline in r.text.splitlines():
60
+ if len(myline) > 20:
61
+ clean.append(myline)
62
+
63
+ masterlist = list(csv.DictReader(StringIO("\n".join(clean))))
65
64
 
66
65
  logger.debug("Get historical data and meld it into current format")
67
66
  # Get the historical data, and meld it into the same format
@@ -82,7 +81,7 @@ def scrape(
82
81
  )
83
82
  reader = list(csv.DictReader(r.text.splitlines()))
84
83
  for row in reader:
85
- line = {}
84
+ line: dict = {}
86
85
  for item in lookup:
87
86
  if not lookup[item]:
88
87
  line[item] = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: warn-scraper
3
- Version: 1.2.158.dev0
3
+ Version: 1.2.159.dev0
4
4
  Summary: Command-line interface for downloading WARN Act notices of qualified plant closings and mass layoffs from state government websites
5
5
  Author-email: Big Local News <biglocalnews@stanford.edu>
6
6
  License-Expression: Apache-2.0
@@ -20,7 +20,7 @@ warn/scrapers/co.py,sha256=83OdikIrWGxt22mlI-_zLSNqJg1NO5C2Xjm3FF6DPYY,18252
20
20
  warn/scrapers/ct.py,sha256=PzRnrq91T2a5IzDWMh0GDxWVLXkN-BtHRIYbutjgQhw,2868
21
21
  warn/scrapers/dc.py,sha256=p1_c7O2R3O-41DmvcLVUIRhQKUewvZZKkzWkBxytN5M,5165
22
22
  warn/scrapers/de.py,sha256=GyM92A-lFwZAfRxgbO-sIWhRfmBEKirzchaPIv-u0o4,1364
23
- warn/scrapers/fl.py,sha256=pBkDo3mcKIjXSkWf469QCGLuyn7gH1YfNeX0AwVsuL8,9642
23
+ warn/scrapers/fl.py,sha256=jxN7zhlSNgcpBcBB01M2RcYJzE8hUsmKg9zS8AHzWI4,9846
24
24
  warn/scrapers/ga.py,sha256=2kYhuK0Q6tkwp56lTuOwIH7W5zX6KpYJkqsp5ehSdgc,10700
25
25
  warn/scrapers/hi.py,sha256=pSplAP15_ZBfQtcywyErmvNcrk7u55TjZj_F0Nqw9L8,5660
26
26
  warn/scrapers/ia.py,sha256=0kOh3EOsXtWYGl5kvwimwFZGpOlu5_qFWhM_-n1MLds,2048
@@ -40,7 +40,7 @@ warn/scrapers/ne.py,sha256=JawuGJ3tCKvMd-N-p03gnltB4rol4QUJshMk2oyMPO4,4143
40
40
  warn/scrapers/nj.py,sha256=nwbMbeQuUJbYRVoyUyKZBmNqvqsXu3Habt-10r8DvZE,2230
41
41
  warn/scrapers/nm.py,sha256=55kDh65uOc-uMO8wuxPHhHN4Aw8Di2Fx66JBds8f2Io,3694
42
42
  warn/scrapers/ny.py,sha256=_nYoawIde4yYtk8-tMG3hekLlSlrKKqULmkBWOUoQJM,2586
43
- warn/scrapers/oh.py,sha256=-_MyuaUGyKgd-XiXMVnf6AHkqOBgAFg0NRRpXGLz-3A,3431
43
+ warn/scrapers/oh.py,sha256=kwHm1feWQwZRdWKnZbDm1c2wdYqNUHJ1myrK6uteyfU,3502
44
44
  warn/scrapers/ok.py,sha256=ZZciyR1jPS4SzS2JSQwhJsDXP_VxA9UkEQvLpxzWzp4,7676
45
45
  warn/scrapers/or.py,sha256=0PjyrW3CHdxtHhqEo3Ob-9B6YckACoBD3K0c4FPQUcg,5208
46
46
  warn/scrapers/pa.py,sha256=j6cYZjKJUht2s829VPAbI2IRJazkqOwbwcVMAcItuIc,5410
@@ -54,11 +54,11 @@ warn/scrapers/va.py,sha256=7Nle7qL0VNPiE653XyaP9HQqSfuJFDRr2kEkjOqLvFM,11269
54
54
  warn/scrapers/vt.py,sha256=d-bo4WK2hkrk4BhCCmLpEovcoZltlvdIUB6O0uaMx5A,1186
55
55
  warn/scrapers/wa.py,sha256=UXdVtHZo_a-XfoiyOooTRfTb9W3PErSZdKca6SRORgs,4282
56
56
  warn/scrapers/wi.py,sha256=ClEzXkwZbop0W4fkQgsb5oHAPUrb4luUPGV-jOKwkcg,4855
57
- warn_scraper-1.2.158.dev0.dist-info/licenses/LICENSE,sha256=ZV-QHyqPwyMuwuj0lI05JeSjV1NyzVEk8Yeu7FPtYS0,585
58
- warn_scraper-1.2.158.dev0.dist-info/METADATA,sha256=eEAoxrMSjuAIXEEF7mpOOan9f74w4CacJtNiWOxPM6E,1780
59
- warn_scraper-1.2.158.dev0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
60
- warn_scraper-1.2.158.dev0.dist-info/entry_points.txt,sha256=poh_oSweObGlBSs1_2qZmnTodlOYD0KfO7-h7W2UQIw,47
61
- warn_scraper-1.2.158.dev0.dist-info/scm_file_list.json,sha256=SBROd7oEfcspIMl6v7yfGzQd2rkWxybkiIXopuTQVL0,4120
62
- warn_scraper-1.2.158.dev0.dist-info/scm_version.json,sha256=XFb9EYQ2iJW5cLXZGITnEVHhw7wZNgPoYMAsYnRCNbU,161
63
- warn_scraper-1.2.158.dev0.dist-info/top_level.txt,sha256=dZfms6N3kqVXufiPOo7YqOrAcUtYfNH_oyGvYUk9FB4,5
64
- warn_scraper-1.2.158.dev0.dist-info/RECORD,,
57
+ warn_scraper-1.2.159.dev0.dist-info/licenses/LICENSE,sha256=ZV-QHyqPwyMuwuj0lI05JeSjV1NyzVEk8Yeu7FPtYS0,585
58
+ warn_scraper-1.2.159.dev0.dist-info/METADATA,sha256=_b2Gr_tQPQ9Z5xGk2aBR2FD68gEKPaWIScQCPsPWGxk,1780
59
+ warn_scraper-1.2.159.dev0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
60
+ warn_scraper-1.2.159.dev0.dist-info/entry_points.txt,sha256=poh_oSweObGlBSs1_2qZmnTodlOYD0KfO7-h7W2UQIw,47
61
+ warn_scraper-1.2.159.dev0.dist-info/scm_file_list.json,sha256=SBROd7oEfcspIMl6v7yfGzQd2rkWxybkiIXopuTQVL0,4120
62
+ warn_scraper-1.2.159.dev0.dist-info/scm_version.json,sha256=lnFVGQ26tYnWMRbtM8vInlCCy60B4aSFEBs6QMOOQFA,161
63
+ warn_scraper-1.2.159.dev0.dist-info/top_level.txt,sha256=dZfms6N3kqVXufiPOo7YqOrAcUtYfNH_oyGvYUk9FB4,5
64
+ warn_scraper-1.2.159.dev0.dist-info/RECORD,,
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "1.2.158",
3
+ "distance": 0,
4
+ "node": "g5d6787f288a27ee88a65617b6cd4ffc3b2b475c5",
5
+ "dirty": true,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-06-29"
8
+ }
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "1.2.157",
3
- "distance": 0,
4
- "node": "g2dc89394a4e2daac88ce2f78548663e8b41d2096",
5
- "dirty": true,
6
- "branch": "HEAD",
7
- "node_date": "2026-06-24"
8
- }