Parse PMDA Japanese recall table page. Table columns: [0] recall_num, [1] pub_date, [2] device_type, [3] generic_name, [4] product_name (has detail link), [5] manufacturer. Detail links use /rgo/MainServlet?recallno=xxx format.
(self, html: str, recall_class: str)
| 2261 | return None |
| 2262 | |
| 2263 | def _parse_recall_table(self, html: str, recall_class: str) -> list[dict]: |
| 2264 | """Parse PMDA Japanese recall table page. |
| 2265 | |
| 2266 | Table columns: [0] recall_num, [1] pub_date, [2] device_type, |
| 2267 | [3] generic_name, [4] product_name (has <a> detail link), [5] manufacturer. |
| 2268 | Detail links use /rgo/MainServlet?recallno=xxx format. |
| 2269 | """ |
| 2270 | results = [] |
| 2271 | try: |
| 2272 | from bs4 import BeautifulSoup |
| 2273 | soup = BeautifulSoup(html, "html.parser") |
| 2274 | for tr in soup.find_all("tr"): |
| 2275 | cells = tr.find_all("td") |
| 2276 | if len(cells) < 5: |
| 2277 | continue |
| 2278 | recall_num = cells[0].get_text(strip=True) |
| 2279 | pub_date_raw = cells[1].get_text(strip=True) |
| 2280 | device_type = cells[2].get_text(strip=True) |
| 2281 | generic_name = cells[3].get_text(strip=True) |
| 2282 | product_name = cells[4].get_text(strip=True) |
| 2283 | manufacturer = cells[5].get_text(strip=True) if len(cells) > 5 else "" |
| 2284 | detail_link = "" |
| 2285 | for cell in cells: |
| 2286 | a_tag = cell.find("a") |
| 2287 | if a_tag and a_tag.get("href"): |
| 2288 | href = a_tag["href"] |
| 2289 | if not href.startswith("http"): |
| 2290 | href = "https://www.info.pmda.go.jp" + href |
| 2291 | if "MainServlet" in href or "kaisyuu" in href: |
| 2292 | detail_link = href |
| 2293 | break |
| 2294 | if not detail_link: |
| 2295 | yy = str(datetime.now().year % 100).zfill(2) |
| 2296 | cls_suffix = "1k" if recall_class == "I" else "2k" |
| 2297 | detail_link = f"https://www.info.pmda.go.jp/kaisyuu/rcidx{yy}-{cls_suffix}.html" |
| 2298 | dm = re.search(r"(\d{4})/(\d{1,2})/(\d{1,2})", pub_date_raw) |
| 2299 | pub_date = f"{dm.group(1)}-{dm.group(2).zfill(2)}-{dm.group(3).zfill(2)}" if dm else "" |
| 2300 | title = f"[Class {recall_class}] {product_name} ({generic_name})" |
| 2301 | if manufacturer: |
| 2302 | title += f" - {manufacturer}" |
| 2303 | results.append({ |
| 2304 | "id": recall_num, |
| 2305 | "title": title, |
| 2306 | "link": detail_link, |
| 2307 | "pub_date": pub_date, |
| 2308 | "description": f"Recall #{recall_num}: {generic_name} / {product_name} by {manufacturer}. Type: {device_type}.", |
| 2309 | }) |
| 2310 | except ImportError: |
| 2311 | pass |
| 2312 | return results |
| 2313 | |
| 2314 | |
| 2315 | # --------------------------------------------------------------------------- |