inspect_reports.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. """Keep public reference reports and readable structure for local design review."""
  2. from html.parser import HTMLParser
  3. from pathlib import Path
  4. from urllib.request import Request, urlopen
  5. import argparse
  6. import hashlib
  7. import json
  8. OUT = Path(__file__).resolve().parent / 'reference'
  9. class ReportParser(HTMLParser):
  10. def __init__(self):
  11. super().__init__()
  12. self.skip = 0
  13. self.lines = []
  14. self.headings = []
  15. self.heading = None
  16. self.links = []
  17. self.anchor = None
  18. self.tables = 0
  19. self.images = 0
  20. def handle_starttag(self, tag, attrs):
  21. attrs = dict(attrs)
  22. if tag in ('script', 'style'):
  23. self.skip += 1
  24. if tag in ('h1', 'h2', 'h3', 'h4'):
  25. self.heading = {'level': tag, 'id': attrs.get('id'), 'text': ''}
  26. self.lines.append('\n')
  27. if tag == 'a':
  28. self.anchor = {'href': attrs.get('href', ''), 'text': ''}
  29. if tag == 'table':
  30. self.tables += 1
  31. if tag == 'img':
  32. self.images += 1
  33. def handle_endtag(self, tag):
  34. if tag in ('script', 'style'):
  35. self.skip -= 1
  36. if tag in ('h1', 'h2', 'h3', 'h4') and self.heading:
  37. self.headings.append(self.heading)
  38. self.heading = None
  39. if tag == 'a' and self.anchor:
  40. self.links.append(self.anchor)
  41. self.anchor = None
  42. if tag in ('h1', 'h2', 'h3', 'h4', 'p', 'li', 'tr', 'section', 'article', 'blockquote'):
  43. self.lines.append('\n')
  44. def handle_data(self, data):
  45. if not self.skip and data.strip():
  46. self.lines.append(data.strip() + ' ')
  47. if self.heading:
  48. self.heading['text'] += data.strip()
  49. if self.anchor:
  50. self.anchor['text'] += data.strip()
  51. def main():
  52. parser = argparse.ArgumentParser()
  53. parser.add_argument('name')
  54. parser.add_argument('url')
  55. args = parser.parse_args()
  56. OUT.mkdir(exist_ok=True)
  57. with urlopen(Request(args.url, headers={'User-Agent': 'Mozilla/5.0'}), timeout=40) as response:
  58. content = response.read()
  59. status = response.status
  60. final_url = response.url
  61. target = OUT / (args.name + '.html')
  62. if target.exists():
  63. assert target.read_bytes() == content, 'Reference changed; retain the earlier version before refreshing'
  64. else:
  65. target.write_bytes(content)
  66. parsed = ReportParser()
  67. parsed.feed(content.decode('utf-8', 'replace'))
  68. readable = '\n'.join(line.strip() for line in ''.join(parsed.lines).splitlines() if line.strip())
  69. (OUT / (args.name + '.txt')).write_text(readable + '\n', encoding='utf-8')
  70. result = {'url': args.url, 'finalUrl': final_url, 'httpStatus': status,
  71. 'bytes': len(content), 'sha256': hashlib.sha256(content).hexdigest(),
  72. 'headings': parsed.headings, 'tables': parsed.tables, 'images': parsed.images,
  73. 'links': parsed.links}
  74. (OUT / (args.name + '.json')).write_text(json.dumps(result, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
  75. print(json.dumps({k: v for k, v in result.items() if k != 'links'}, ensure_ascii=False, indent=2))
  76. if __name__ == '__main__':
  77. main()