You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python获取任意博客最新文章发布日期?求更优实现方案

如何高效提取任意博客最新文章的发布日期?

我希望编写一个脚本,输入任意博客的URL即可返回其最新文章的发布日期。目前我已尝试两种方法:
第一种是使用htmldate,但该工具在此场景下错误率较高,代码示例如下:

import requests
from htmldate import find_date

url = 'xxx'

# Check URL content
response = requests.get(url)

if response.status_code == 200:
    html_content = response.text
else:
    print(f"Failed to fetch HTML content. Status code: {response.status_code}")

# Use HTML content with htmldate
if response.status_code == 200:
    date = find_date(html_content, outputformat='%d %B %Y')
    print(date)
else:
    print("Skipping htmldate processing due to failed HTML content retrieval.")

第二种是使用BeautifulSoup,但需要预先提供可能包含日期的各类HTML标签列表,代码示例如下:

import requests
from bs4 import BeautifulSoup
from dateutil import parser

def get_latest_post_date(url):
    try:
        # Send HTTP GET request to blog URL
        response = requests.get(url)

        # Check if request was successful
        if response.status_code == 200:
            # Parse HTML content of page
            soup = BeautifulSoup(response.text, 'html.parser')

            # List of common HTML elements that might contain publication date
            date_elements = [
                soup.find('time'),
                soup.find('span', class_='date'),
                soup.find('span', class_='post-date'),
                soup.find('span', class_='dated-posted'),
                soup.find('div', class_='post-date'),
                soup.find('span', {'itemprop': 'datePublished'}),
                soup.find('meta', {'itemprop': 'datePublished'}),
                soup.find('span', {'property': 'article:published_time'}),
                soup.find('meta', {'property': 'article:published_time'}),
                # Add more elements based on the structure of the specific blog
            ]

            # Find first non-empty date element
            date_element = next((element for element in date_elements if element and element.text.strip()), None)

            if date_element:
                # Extract date string and parse into datetime object
                date_string = date_element.text.strip()
                date = parser.parse(date_string)
                return date.strftime('%Y-%m-%d %H:%M:%S')  # Format the date as needed
            else:
                return "Date not found on the page"

        else:
            return f"Failed to retrieve the page. Status code: {response.status_code}"

    except Exception as e:
        return f"Error: {e}"

blog_url = 'xxx'
latest_post_date = get_latest_post_date(blog_url)

print(f"The date of the latest post on {blog_url} is: {latest_post_date}")

请问是否存在更有效的实现方法?


更高效的实现方案

1. 优先抓取RSS/Atom订阅源

绝大多数博客都会提供RSS或Atom订阅源,这些源的日期格式标准统一,提取难度极低,是最可靠的途径。可以通过两种方式自动发现订阅源:

  • 解析HTML中的<link>标签,查找rel="alternate"且类型为application/rss+xml或application/atom+xml的链接
  • 尝试拼接常见的订阅路径(如/rss、/feed、/atom.xml),验证是否可访问

代码示例:

import requests
from bs4 import BeautifulSoup
import feedparser
from dateutil import parser

def find_feed_url(blog_url):
    try:
        response = requests.get(blog_url, headers={"User-Agent": "Mozilla/5.0"})
        if response.status_code != 200:
            return None
        soup = BeautifulSoup(response.text, 'html.parser')
        # 查找页面中的RSS/Atom链接
        feed_links = soup.find_all('link', rel='alternate')
        for link in feed_links:
            if link.get('type') in ['application/rss+xml', 'application/atom+xml']:
                return link.get('href')
        # 尝试常见的订阅路径
        common_paths = ['/rss', '/feed', '/atom.xml', '/feed.xml']
        for path in common_paths:
            feed_url = blog_url.rstrip('/') + path
            test_response = requests.head(feed_url, headers={"User-Agent": "Mozilla/5.0"})
            if test_response.status_code == 200:
                return feed_url
        return None
    except Exception:
        return None

def get_latest_date_from_feed(feed_url):
    try:
        feed = feedparser.parse(feed_url)
        if not feed.entries:
            return None
        # 取第一个条目(通常为最新文章)的日期
        latest_entry = feed.entries[0]
        # 兼容不同的日期字段名
        date_fields = ['published', 'updated', 'pubDate', 'dc_date']
        for field in date_fields:
            if field in latest_entry:
                return parser.parse(latest_entry[field]).strftime('%Y-%m-%d %H:%M:%S')
        return None
    except Exception:
        return None

2. 优化HTML日期提取逻辑

如果没有订阅源,优化BeautifulSoup的提取逻辑,覆盖更多场景:

  • 优先处理带datetime属性的<time>标签
  • 解析meta标签的content属性(之前的代码忽略了这一点)
  • 使用CSS选择器匹配所有含日期相关类名的元素
  • 用正则匹配页面中所有可能的日期字符串

改进后的HTML提取函数:

import re
from bs4 import BeautifulSoup
from dateutil import parser

def get_latest_date_from_html(html_content):
    soup = BeautifulSoup(html_content, 'html.parser')
    date_candidates = []

    # 处理带datetime属性的time标签
    time_tags = soup.find_all('time')
    for tag in time_tags:
        if datetime_val := tag.get('datetime'):
            date_candidates.append(datetime_val)
        elif text_val := tag.text.strip():
            date_candidates.append(text_val)

    # 处理meta标签中的日期属性
    meta_tags = soup.find_all('meta', attrs={
        'property': ['article:published_time', 'og:published_time'],
        'itemprop': ['datePublished', 'dateModified']
    })
    for tag in meta_tags:
        if content_val := tag.get('content'):
            date_candidates.append(content_val)

    # 匹配带日期类名的元素
    common_selectors = [
        '.date', '.post-date', '.published', '.entry-date',
        '[class*="date"]', '[class*="published"]'
    ]
    for selector in common_selectors:
        for elem in soup.select(selector):
            if text_val := elem.text.strip():
                date_candidates.append(text_val)

    # 正则匹配页面中所有可能的日期格式
    date_patterns = [
        r'\d{4}-\d{2}-\d{2}',
        r'\d{2}/\d{2}/\d{4}',
        r'\w+ \d{1,2}, \d{4}',
        r'\d{1,2} \w+ \d{4}'
    ]
    for pattern in date_patterns:
        date_candidates.extend(re.findall(pattern, html_content))

    # 解析所有候选日期,返回最新的一个
    parsed_dates = []
    for candidate in date_candidates:
        try:
            parsed_date = parser.parse(candidate, fuzzy=True)
            parsed_dates.append(parsed_date)
        except:
            continue
    if parsed_dates:
        return max(parsed_dates).strftime('%Y-%m-%d %H:%M:%S')
    return "Date not found"

3. 多策略兜底整合

将RSS提取、优化后的HTML提取、htmldate按优先级组合,形成 fallback 机制:

  1. 优先尝试RSS/Atom源提取日期
  2. 失败则用优化后的HTML逻辑提取
  3. 最后用htmldate作为兜底方案

完整整合脚本:

import requests

def get_latest_post_date(url):
    headers = {"User-Agent": "Mozilla/5.0"}
    # 第一步:尝试RSS/Atom源
    feed_url = find_feed_url(url)
    if feed_url:
        feed_date = get_latest_date_from_feed(feed_url)
        if feed_date:
            return feed_date

    # 第二步:尝试优化后的HTML提取
    response = requests.get(url, headers=headers)
    if response.status_code != 200:
        return f"Failed to retrieve page. Status code: {response.status_code}"
    html_date = get_latest_date_from_html(response.text)
    if html_date != "Date not found":
        return html_date

    # 第三步:htmldate兜底
    try:
        from htmldate import find_date
        htmldate_result = find_date(response.text, outputformat='%Y-%m-%d %H:%M:%S')
        if htmldate_result:
            return htmldate_result
    except ImportError:
        pass

    return "Date not found on the page"

# 测试调用
blog_url = "https://example-blog.com"
print(f"Latest post date: {get_latest_post_date(blog_url)}")

额外优化建议

  • 反爬处理:给requests添加User-Agent头,避免被网站拦截
  • 结果缓存:对已处理的URL缓存结果,减少重复请求
  • 时区统一:解析日期时指定时区(如parser.parse(candidate, tzinfo=pytz.utc)),确保日期一致性

内容的提问来源于stack exchange,提问作者Sebastian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 20:18:12