如何把公众号文章转为markdown?

最近在把公众号文章导入网站,于是做了个小工具把文章转化为markdown。其中图片会转为外链形式,代码框等格式会保留,感觉十分方便,因此分享。 ```python import requests from bs4 import BeautifulSoup import markdownify import re url = "https://mp.weixin.qq.com/s/your-article-link" # 添加请求头,模拟浏览器访问 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } html = requests.get(url, headers=headers).text soup = BeautifulSoup(html, "html.parser") # 提取标题 title_tag = soup.find(id="activity-name") if not title_tag: title_tag = soup.find("h1", class_="rich_media_title") if not title_tag: title_tag = soup.find("h2", class_="rich_media_title") title = title_tag.get_text(strip=True) if title_tag else "未找到标题" print(f"文章标题: {title}") # 提取作者和发布时间(如果有) author_tag = soup.find(id="js_name") author = author_tag.get_text(strip=True) if author_tag else "" publish_time_tag = soup.find(id="publish_time") if not publish_time_tag: publish_time_tag = soup.find("em", id="post-date") publish_time = publish_time_tag.get_text(strip=True) if publish_time_tag else "" if author: print(f"作者: {author}") if publish_time: print(f"发布时间: {publish_time}") # 打印调试信息 print("\n查找 id='js_content' 的元素...") content = soup.find(id="js_content") print(f"找到的内容: {content is not None}") if content is None: # 尝试其他可能的选择器 print("尝试其他选择器...") content = soup.find("div", class_="rich_media_content") print(f"找到 class='rich_media_content': {content is not None}") if content: # 提取所有图片信息 images = content.find_all('img') print(f"\n找到 {len(images)} 张图片") image_info = [] for idx, img in enumerate(images, 1): img_data = { 'index': idx, 'data-src': img.get('data-src', ''), 'src': img.get('src', ''), 'alt': img.get('alt', ''), 'data-ratio': img.get('data-ratio', ''), 'data-w': img.get('data-w', '') } image_info.append(img_data) # 替换图片标签为带链接的markdown格式 img_url = img_data['data-src'] or img_data['src'] if img_url: # 创建新的img标签,确保src属性正确 img['src'] = img_url if 'data-src' in img.attrs: del img['data-src'] print(f"图片 {idx}: {img_url[:100]}..." if len(img_url) > 100 else f"图片 {idx}: {img_url}") # 在转换为markdown之前,先处理小标题 # 微信公众号的小标题通常用 <h2>, <h3>, <strong>, <p> 加粗等标记 # 查找所有可能的小标题元素 sections = content.find_all(['h1', 'h2', 'h3', 'h4', 'h5', 'h6']) print(f"找到 {len(sections)} 个标题标签(h1-h6)") # 查找使用strong或b标签且单独成段的文本(常见的小标题格式) paragraphs = content.find_all('p') strong_titles = [] number_titles = [] for p in paragraphs: text = p.get_text(strip=True) # 检查段落是否只包含一个strong/b标签 strongs = p.find_all(['strong', 'b']) if len(strongs) == 1 and text == strongs[0].get_text(strip=True): # 判断是否像标题(长度合适,不是纯数字) if 2 <= len(text) <= 50 and not text.isdigit(): strong_titles.append(text) # 将这个段落转换为h3标签以便markdown转换时识别 new_h3 = soup.new_tag('h3') new_h3.string = text p.replace_with(new_h3) # 检查是否是数字开头的小标题格式(如:"1 改他作甚?") elif re.match(r'^\d+[\s\.、]+.{2,50}[?!。]?$', text): number_titles.append(text) # 将这个段落转换为h2标签 new_h2 = soup.new_tag('h2') new_h2.string = text p.replace_with(new_h2) print(f"找到 {len(strong_titles)} 个加粗格式的小标题") if strong_titles: print("识别的加粗小标题:", strong_titles) print(f"找到 {len(number_titles)} 个数字编号的小标题") if number_titles: print("识别的编号小标题:", number_titles) # 转换为markdown md = markdownify.markdownify(str(content), heading_style="atx") # 后处理:识别数字编号的小标题(在单独一行且符合标题模式) lines = md.split('\n') processed_lines = [] detected_subtitles = [] for i, line in enumerate(lines): stripped = line.strip() # 匹配数字开头的小标题:数字 + 空格/点/顿号 + 2-30个字符 + 可选的标点 if re.match(r'^\d+[\s\.、]+.{2,30}[?!。]?$', stripped): # 确保不是列表项的一部分(前后有空行或是第一行) prev_empty = (i == 0 or not lines[i-1].strip()) next_empty = (i == len(lines)-1 or not lines[i+1].strip()) if prev_empty or next_empty: detected_subtitles.append(stripped) # 转换为二级标题 processed_lines.append(f'## {stripped}') continue processed_lines.append(line) md = '\n'.join(processed_lines) print(f"后处理识别到 {len(detected_subtitles)} 个小标题") if detected_subtitles: print("识别的小标题:", detected_subtitles) # 构建完整的markdown内容,包含标题和元信息 full_md = f"# {title}\n\n" if author or publish_time: full_md += "> " if author: full_md += f"作者: {author}" if author and publish_time: full_md += " | " if publish_time: full_md += f"发布时间: {publish_time}" full_md += "\n\n" full_md += "---\n\n" full_md += md # 保存markdown文件 open("article.md","w").write(full_md) print(f"\n已保存到 article.md,内容长度: {len(full_md)} 字符") # 保存图片信息到单独的文件 with open("images_info.txt", "w") as f: f.write(f"文章URL: {url}\n") f.write(f"文章标题: {title}\n") if author: f.write(f"作者: {author}\n") if publish_time: f.write(f"发布时间: {publish_time}\n") f.write(f"共找到 {len(images)} 张图片\n\n") for img_data in image_info: f.write(f"=== 图片 {img_data['index']} ===\n") f.write(f"URL: {img_data['data-src'] or img_data['src']}\n") if img_data['alt']: f.write(f"描述: {img_data['alt']}\n") if img_data['data-w']: f.write(f"宽度: {img_data['data-w']}\n") if img_data['data-ratio']: f.write(f"比例: {img_data['data-ratio']}\n") f.write("\n") print(f"已保存图片信息到 images_info.txt") else: print("未找到文章内容,保存 HTML 以供检查") open("debug.html", "w").write(html) print("已保存原始 HTML 到 debug.html") ```

评论

留下评论

邮箱仅用于识别,不会公开

支持 KaTeX:$...$ 行内 · $$...$$ 独立公式
加载评论中...