Java 从网页中提取日期
我想从网页中提取不同格式的日期。我正在使用Selenium2 Java API与浏览器交互。我还使用jQuery进一步与文档交互。因此,这两个层的解决方案都是受欢迎的 在不同的地区,日期可以有非常不同的格式。此外,月份名称可以写成文本或数字。我需要尽可能多地匹配日期,而且我知道有很多组合 例如,如果我有如下HTML元素:Java 从网页中提取日期,java,jquery,date,extraction,selenium-webdriver,Java,Jquery,Date,Extraction,Selenium Webdriver,我想从网页中提取不同格式的日期。我正在使用Selenium2 Java API与浏览器交互。我还使用jQuery进一步与文档交互。因此,这两个层的解决方案都是受欢迎的 在不同的地区,日期可以有非常不同的格式。此外,月份名称可以写成文本或数字。我需要尽可能多地匹配日期,而且我知道有很多组合 例如,如果我有如下HTML元素: <div class="tag_view"> Last update: May,22,2011 View :40 </div> &l
<div class="tag_view">
Last update: May,22,2011
View :40
</div>
<span class="relativetime" title="2011-05-13 14:45:06Z">May 13 at 14:45</span>
现在应该将其转换为常规Java日期对象
更新
这应该适用于任何网页的HTML,日期可以包含在任何格式的任何元素中。例如,在Stackoverflow上,源代码如下所示:
<div class="tag_view">
Last update: May,22,2011
View :40
</div>
<span class="relativetime" title="2011-05-13 14:45:06Z">May 13 at 14:45</span>
5月13日14:45
我希望它是以最有效的方式完成的,我想这将是一个jQuery选择器或过滤器,它返回一个标准化的日期表示。但是我愿意接受你的建议。因为我们不能将自己局限于任何特定的元素类型或任何元素的子元素,所以你基本上是在整个页面的文本中搜索日期。唯一有效的方法就是使用正则表达式。因为您要查找任何格式的日期,所以需要为每个可接受的格式使用正则表达式。一旦定义了它们,只需编译正则表达式并运行如下操作:
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]));
}
你可以通过谷歌搜索找到更多的日期正则表达式,或者自己制作,它们非常简单。需要注意的一点是:您可能可以结合上面的一些正则表达式来创建一个更高效的程序。我会非常小心,这可能会导致您的代码很快变得难以阅读。按日期格式执行一个正则表达式似乎更干净。可以考虑使用GETTeX获取元素文本,然后拆分字符串,比如-< /P>
String s = selenium.getText("css=span.relativetime");
String date = s.split("Last update:")[1].split("View :")[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);
}
选择一个你更愿意做这项工作的地方(java vs javascript)。我们两种方式都可以。此外,您是否知道某些分隔符是否总是围绕文本(例如,上面的“更新:”和“查看:”围绕日期),您当然会遇到9/10/11的问题。2011年9月10日还是2011年10月9日?(或者11月……或者1911年……)@drachenstern:不,每次我解析它时,它可能会非常不同。我相应地更新了我的问题-@Jeff B:是的,确实如此,我需要以某种方式识别这些模式中的大多数。那么,你有点卡住了,因为你无法从“3/5/10”和类似的结构中获得明确的日期。你可以决定你想对他们做出什么样的解释,但在一般情况下,你不能通过编程来了解作者的意思。你是对的。我可以使用最可能的日期含义排序。这是非常具体的,并不普遍适用