2011-05-23 40 views
4

我想從網頁中提取不同格式的日期。我正在使用Selenium2 Java API與瀏覽器進行交互。另外我使用jQuery來進一步與文檔進行交互。所以,這兩層的解決方案都是受歡迎的。從網頁中提取日期

日期在不同的語言環境中可以有非常不同的格式。此外,月份名稱可以寫成文本或數字。我需要匹配儘可能多的日期,並且我意識到有很多組合。

例如,如果我有這樣的HTML元素:

<div class="tag_view"> 
    Last update: May,22,2011 
    View :40 
</div> 

我想要的日期的相關部分被提取和識別:

May,22,2011 

這個現在應該轉換爲常規的Java Date對象。

更新

這應該與任何網頁的HTML工作,日期可以包含在任何格式的任何元素。例如在這裏#2的源代碼如下所示:

<span class="relativetime" title="2011-05-13 14:45:06Z">May 13 at 14:45</span> 

我希望它做的最有效的方法,我想這將是一個jQuery選擇或過濾器,其返回一個標準化的日期表示。但我接受你的建議。

+1

選擇一個你寧願做工作的地方(java vs javascript)。我們可以以任何方式做到這一點。另外,你知道某些分隔符是否總是圍繞文本(例如,在日期的上方有「update:」和「view:」) – jcolebrand 2011-05-23 16:54:03

+2

你當然會遇到9/10/11的問題。 2011年9月10日或2011年10月9日? (或11月......或1911年......) – 2011-05-23 17:47:06

+0

@drachenstern:不,每次我解析它時都會有很大的不同。我相應地更新了我的問題 - @Jeff B:是的,我不知何故需要識別大部分這些模式 – Alp 2011-05-23 17:53:29

回答

0

我會回答這個自己,因爲我有一個有效的解決方案上來。我欣賞評論。

/** 
* Extract date 
* 
* @return Date object 
* @throws ParseException 
*/ 
public Date extractDate(String text) throws ParseException { 
    Date date = null; 
    boolean dateFound = false; 

    String year = null; 
    String month = null; 
    String monthName = null; 
    String day = null; 
    String hour = null; 
    String minute = null; 
    String second = null; 
    String ampm = null; 

    String regexDelimiter = "[-:\\/.,]"; 
    String regexDay = "((?:[0-2]?\\d{1})|(?:[3][01]{1}))"; 
    String regexMonth = "(?:([0]?[1-9]|[1][012])|(Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Sept|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?))"; 
    String regexYear = "((?:[1]{1}\\d{1}\\d{1}\\d{1})|(?:[2]{1}\\d{3}))"; 
    String regexHourMinuteSecond = "(?:(?:\\s)((?:[0-1][0-9])|(?:[2][0-3])|(?:[0-9])):([0-5][0-9])(?::([0-5][0-9]))?(?:\\s?(am|AM|pm|PM))?)?"; 
    String regexEndswith = "(?![\\d])"; 

    // DD/MM/YYYY 
    String regexDateEuropean = 
     regexDay + regexDelimiter + regexMonth + regexDelimiter + regexYear + regexHourMinuteSecond + regexEndswith; 

    // MM/DD/YYYY 
    String regexDateAmerican = 
     regexMonth + regexDelimiter + regexDay + regexDelimiter + regexYear + regexHourMinuteSecond + regexEndswith; 

    // YYYY/MM/DD 
    String regexDateTechnical = 
     regexYear + regexDelimiter + regexMonth + regexDelimiter + regexDay + regexHourMinuteSecond + regexEndswith; 

    // see if there are any matches 
    Matcher m = checkDatePattern(regexDateEuropean, text); 
    if (m.find()) { 
     day = m.group(1); 
     month = m.group(2); 
     monthName = m.group(3); 
     year = m.group(4); 
     hour = m.group(5); 
     minute = m.group(6); 
     second = m.group(7); 
     ampm = m.group(8); 
     dateFound = true; 
    } 

    if(!dateFound) { 
     m = checkDatePattern(regexDateAmerican, text); 
     if (m.find()) { 
      month = m.group(1); 
      monthName = m.group(2); 
      day = m.group(3); 
      year = m.group(4); 
      hour = m.group(5); 
      minute = m.group(6); 
      second = m.group(7); 
      ampm = m.group(8); 
      dateFound = true; 
     } 
    } 

    if(!dateFound) { 
     m = checkDatePattern(regexDateTechnical, text); 
     if (m.find()) { 
      year = m.group(1); 
      month = m.group(2); 
      monthName = m.group(3); 
      day = m.group(3); 
      hour = m.group(5); 
      minute = m.group(6); 
      second = m.group(7); 
      ampm = m.group(8); 
      dateFound = true; 
     } 
    } 

    // construct date object if date was found 
    if(dateFound) { 
     String dateFormatPattern = ""; 
     String dayPattern = ""; 
     String dateString = ""; 

     if(day != null) { 
      dayPattern = "d" + (day.length() == 2 ? "d" : ""); 
     } 

     if(day != null && month != null && year != null) { 
      dateFormatPattern = "yyyy MM " + dayPattern; 
      dateString = year + " " + month + " " + day; 
     } else if(monthName != null) { 
      if(monthName.length() == 3) dateFormatPattern = "yyyy MMM " + dayPattern; 
      else dateFormatPattern = "yyyy MMMM " + dayPattern; 
      dateString = year + " " + monthName + " " + day; 
     } 

     if(hour != null && minute != null) { 
      //TODO ampm 
      dateFormatPattern += " hh:mm"; 
      dateString += " " + hour + ":" + minute; 
      if(second != null) { 
       dateFormatPattern += ":ss"; 
       dateString += ":" + second; 
      } 
     } 

     if(!dateFormatPattern.equals("") && !dateString.equals("")) { 
      //TODO support different locales 
      SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatPattern.trim(), Locale.US); 
      date = dateFormat.parse(dateString.trim()); 
     } 
    } 

    return date; 
} 

private Matcher checkDatePattern(String regex, String text) { 
    Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.DOTALL); 
    return p.matcher(text); 
} 
1

由於我們無法將自己限制爲任何特定元素類型或任何元素的子元素,因此您基本上正在討論在整個頁面的文本中搜索日期。以任何一種效率來做到這一點的唯一方法是使用正則表達式。由於您在以任何格式查找日期,因此您需要針對每種可接受格式的正則表達式。一旦你確定這些是什麼,只是編譯正則表達式和運行是這樣的:通過谷歌搜索周圍

var datePatterns = new Array(); 
datePatterns.push(/\d\d\/\d\d\/\d\d\d\d/g); 
datePatterns.push(/\d\d\d\d\/\d\d\/\d\d/g); 
... 

var stringToSearch = $('body').html(); // change this to be more specific if at all possible 
var allMatches = new Array(); 
for (datePatternIndex in datePatterns){ 
    allMatches.push(stringToSearch.match(datePatterns[datePatternIndex])); 
} 

你可以找到更多日期的正則表達式,或者讓他們自己,他們是很容易的。有一件事要注意:你可以結合上面的一些正則表達式來創建一個更高效的程序。我對此非常小心,它可能會導致您的代碼很難快速閱讀。每個日期格式做一個正則表達式似乎更清晰。

0

你可以考慮使用的getText來獲得元素的文本,然後分割字符串,如 -

String s = selenium.getText("css=span.relativetime"); 
String date = s.split("Last update:")[1].split("View :")[0]; 
+0

這是非常具體的,並不普遍適用 – Alp 2011-05-25 08:48:04