Извлечь даты с веб-страницы - PullRequest
4 голосов
/ 23 мая 2011

Я хочу извлечь даты из разных форматов из веб-страниц. Я использую Selenium2 Java API для взаимодействия с браузером. Также я использую jQuery для дальнейшего взаимодействия с документом. Итак, решения для обоих слоев приветствуются.

Даты могут иметь очень разные форматы в разных локалях. Кроме того, названия месяцев могут быть написаны как текст или как число. Мне нужно сопоставить как можно больше дат, и я осознаю тот факт, что существует много комбинаций.

Например, если у меня есть такой HTML-элемент:

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

Я хочу, чтобы соответствующая часть даты была извлечена и распознана:

May,22,2011

Теперь он должен быть преобразован в обычный объект Java Date.

Обновление

Это должно работать с HTML с любой веб-страницы, дата может содержаться в любом элементе в любом формате. Например, здесь, в Stackoverflow, исходный код выглядит так:

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

Я хочу, чтобы это было сделано наиболее эффективным способом, и я предполагаю, что это будет селектор или фильтр jQuery, который возвращает стандартизированное представление даты. Но я открыт для ваших предложений.

Ответы [ 3 ]

1 голос
/ 23 мая 2011

Поскольку мы не можем ограничивать себя каким-либо конкретным типом элемента или дочерним элементом какого-либо элемента, вы в основном говорите о поиске дат по всему тексту страницы.Единственный способ сделать это с любой эффективностью - это использовать регулярные выражения.Поскольку вы ищете даты в любом формате, вам нужно регулярное выражение для каждого приемлемого формата.Как только вы определите, что это такое, просто скомпилируйте регулярные выражения и запустите что-то вроде:

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 голосов
/ 25 мая 2011

Я отвечу на это сам, потому что я нашел рабочее решение. Я ценю комментарии, хотя.

/**
 * 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);
}
0 голосов
/ 25 мая 2011

Вы можете использовать getText для получения текста элемента, а затем разделить строку, например -

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