warn-scraper 1.2.159.dev0__py3-none-any.whl → 1.2.161.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
@@ -4,8 +4,10 @@ import re
4
4
  from os.path import exists
5
5
  from pathlib import Path
6
6
 
7
+ import niquests
7
8
  import pdfplumber
8
- import requests
9
+
10
+ # import requests
9
11
  import tenacity
10
12
  import urllib3
11
13
  from bs4 import BeautifulSoup
@@ -51,13 +53,9 @@ def scrape(
51
53
  """
52
54
  output_csv = data_dir / "fl.csv"
53
55
  cache = Cache(cache_dir) # ~/.warn-scraper/cache
54
- # FL site requires realistic User-Agent.
55
- headers = {
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"
57
- }
58
- # url = "https://floridajobs.org/office-directory/division-of-workforce-services/workforce-programs/reemployment-and-emergency-assistance-coordination-team-react/warn-notices"
56
+ session = niquests.Session()
59
57
  url = "https://floridajobs.org/workforce-resources/worker-adjustment-and-retraining-notification-(warn)"
60
- response = requests.get(url, headers=headers, verify=True)
58
+ response = session.get(url)
61
59
  logger.debug(f"Request status is {response.status_code} for {url}")
62
60
  html = response.text
63
61
  details = pq(html)("div.contact-details")
@@ -83,9 +81,9 @@ def scrape(
83
81
  # Loop through years and scrape data
84
82
  for year_url in href_lookup.values():
85
83
  if "PDF" in year_url:
86
- rows_to_add = _scrape_pdf(cache, cache_dir, year_url, headers)
84
+ rows_to_add = _scrape_pdf(cache, cache_dir, year_url, session)
87
85
  else:
88
- html_pages = _scrape_html(cache, year_url, headers)
86
+ html_pages = _scrape_html(cache, year_url, session)
89
87
  rows_to_add = _html_to_rows(html_pages)
90
88
  # Convert rows to dicts
91
89
  rows_as_dicts = [dict(zip(FIELDS, row)) for row in rows_to_add]
@@ -101,9 +99,9 @@ def scrape(
101
99
  # note: no max amount of retries (recursive scraping)
102
100
  @tenacity.retry(
103
101
  wait=tenacity.wait_exponential(),
104
- retry=tenacity.retry_if_exception_type(requests.HTTPError),
102
+ retry=tenacity.retry_if_exception_type(niquests.HTTPError),
105
103
  )
106
- def _scrape_html(cache, url, headers, page=1):
104
+ def _scrape_html(cache, url, session, page=1):
107
105
  urllib3.disable_warnings() # sidestep SSL error
108
106
  # extract year from URL
109
107
  year = _extract_year(url)
@@ -124,7 +122,7 @@ def _scrape_html(cache, url, headers, page=1):
124
122
  raise FileNotFoundError
125
123
  except FileNotFoundError:
126
124
  # scrape & cache html
127
- response = requests.get(url, headers=headers, verify=False)
125
+ response = session.get(url)
128
126
  logger.debug(f"Request status is {response.status_code} for {url}")
129
127
  response.raise_for_status()
130
128
  page_text = response.text
@@ -145,7 +143,7 @@ def _scrape_html(cache, url, headers, page=1):
145
143
  "href"
146
144
  ) # /WarnList/Records?year=XXXX&page=X
147
145
  # recursively make list of all the next pages' html
148
- pages_html = _scrape_html(cache, url, headers, next_page)
146
+ pages_html = _scrape_html(cache, url, session, next_page)
149
147
  # add the current page to the recursive list
150
148
  pages_html.append(page_text)
151
149
  return pages_html
@@ -173,9 +171,9 @@ def _html_to_rows(page_text):
173
171
  # download and scrape pdf
174
172
  @tenacity.retry(
175
173
  wait=tenacity.wait_exponential(),
176
- retry=tenacity.retry_if_exception_type(requests.HTTPError),
174
+ retry=tenacity.retry_if_exception_type(niquests.HTTPError),
177
175
  )
178
- def _scrape_pdf(cache, cache_dir, url, headers):
176
+ def _scrape_pdf(cache, cache_dir, url, session):
179
177
  # sidestep SSL error
180
178
  urllib3.disable_warnings()
181
179
  # extract year from URL
@@ -184,7 +182,7 @@ def _scrape_pdf(cache, cache_dir, url, headers):
184
182
  download = ""
185
183
  # download pdf if not in the cache
186
184
  if not exists(pdf_cache_key):
187
- response = requests.get(url, headers=headers, verify=False)
185
+ response = session.get(url)
188
186
  logger.debug(f"Request status is {response.status_code} for {url}")
189
187
  response.raise_for_status()
190
188
  # download & cache pdf
warn/scrapers/md.py CHANGED
@@ -61,6 +61,8 @@ def scrape(
61
61
  html_list.append(html) # Save the source HTML for parsing also
62
62
 
63
63
  old_pages = [
64
+ "warn2025.shtml",
65
+ "warn2024.shtml",
64
66
  "warn2023.shtml",
65
67
  "warn2022.shtml",
66
68
  "warn2021.shtml",
@@ -83,6 +85,7 @@ def scrape(
83
85
  filename = f"md/{href}.html"
84
86
 
85
87
  if href not in old_pages:
88
+ logger.debug(f"Trying special handling on {href}")
86
89
  sleep(naptime) # Try to stop blocked connections by being less aggressive
87
90
  r = utils.get_url(url, headers=request_headers, verify=request_verify)
88
91
  r.encoding = "utf-8"
@@ -116,6 +119,8 @@ def scrape(
116
119
  row_list = table.find_all("tr")
117
120
 
118
121
  # If it's not the first page, slice off the header
122
+ if i == 0:
123
+ logger.debug(f"Found possible header row: {row_list[0]}")
119
124
  if i > 0:
120
125
  row_list = row_list[1:]
121
126
 
@@ -123,6 +128,10 @@ def scrape(
123
128
  for row in row_list:
124
129
  # Get the cells
125
130
  cell_list = row.find_all("td")
131
+ if not cell_list:
132
+ cell_list = row.find_all(
133
+ "th"
134
+ ) # Alternate approach for first page's header
126
135
 
127
136
  # Clean them up
128
137
  cell_list = [_clean_text(c.text) for c in cell_list]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: warn-scraper
3
- Version: 1.2.159.dev0
3
+ Version: 1.2.161.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=jxN7zhlSNgcpBcBB01M2RcYJzE8hUsmKg9zS8AHzWI4,9846
23
+ warn/scrapers/fl.py,sha256=U0XoNQr8S_9IhPutemMpDKSY8IjXf1ZepR-QezGypj4,9410
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
@@ -30,7 +30,7 @@ warn/scrapers/in.py,sha256=0hOCdbUyls3xX7Q1z5OB6yCrXJFpsu2CmvfwRh9NTfY,2202
30
30
  warn/scrapers/ks.py,sha256=F_3biEMF7zgCX2XVuUACR74Vyzapta4SaM9SY3EuZCU,1266
31
31
  warn/scrapers/ky.py,sha256=7kJTNOzxChyXlcyBImmdwwmrczYksU8XNxbhQ2owmJs,9688
32
32
  warn/scrapers/la.py,sha256=52i7ICYH0R7omFyu-kmKi_s-8Rhy0vaPjNIKlW_OMC8,6938
33
- warn/scrapers/md.py,sha256=hwgxXQnhyBWm8qF1dvxIThAX1MkrZbXLwRI9inO5t8g,4060
33
+ warn/scrapers/md.py,sha256=Zjudr5X8-E3fjBXbOqnB830XEZqLznGzQbaJ5HSY0zQ,4425
34
34
  warn/scrapers/me.py,sha256=q36F4yJ7hvZsLayA3uBS1romo4X3Qf-sEi2Y7LAQCi8,1172
35
35
  warn/scrapers/mi.py,sha256=Ppyawp4nbzSBODuzDKeqnO9_9do5MFwK4Y_f3uc6blE,5846
36
36
  warn/scrapers/mo.py,sha256=wnnwQAiVPwuheMqptMXZpyQdiKNghhKwTO-Bnh9oXoU,3492
@@ -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.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,,
57
+ warn_scraper-1.2.161.dev0.dist-info/licenses/LICENSE,sha256=ZV-QHyqPwyMuwuj0lI05JeSjV1NyzVEk8Yeu7FPtYS0,585
58
+ warn_scraper-1.2.161.dev0.dist-info/METADATA,sha256=-bmCHUv5C4mH2zIWGeKJL_rXeulZVk7G2y4csorP4RA,1780
59
+ warn_scraper-1.2.161.dev0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
60
+ warn_scraper-1.2.161.dev0.dist-info/entry_points.txt,sha256=poh_oSweObGlBSs1_2qZmnTodlOYD0KfO7-h7W2UQIw,47
61
+ warn_scraper-1.2.161.dev0.dist-info/scm_file_list.json,sha256=SBROd7oEfcspIMl6v7yfGzQd2rkWxybkiIXopuTQVL0,4120
62
+ warn_scraper-1.2.161.dev0.dist-info/scm_version.json,sha256=2zu8ZMmGXe2W6-SIbF-03pXZmDDOzYDnby3i_6KPk80,161
63
+ warn_scraper-1.2.161.dev0.dist-info/top_level.txt,sha256=dZfms6N3kqVXufiPOo7YqOrAcUtYfNH_oyGvYUk9FB4,5
64
+ warn_scraper-1.2.161.dev0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (82.0.1)
2
+ Generator: setuptools (83.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "1.2.160",
3
+ "distance": 0,
4
+ "node": "gc0831585f2289f68c9329c4e03d053ec0b80b19e",
5
+ "dirty": true,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-07-05"
8
+ }
@@ -1,8 +0,0 @@
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
- }