2011-05-23 5 views
4

Je veux extraire des dates avec différents formats hors des pages Web. J'utilise l'API Java Selenium2 pour interagir avec le navigateur. J'utilise également jQuery pour interagir davantage avec le document. Ainsi, les solutions pour les deux couches sont les bienvenues.Extraire les dates de la page Web

Les dates peuvent avoir des formats très différents selon les paramètres régionaux. En outre, les noms de mois peuvent être écrits en tant que texte ou en tant que nombre. J'ai besoin de faire correspondre autant de dates que possible, et je suis conscient du fait qu'il existe de nombreuses combinaisons.

Par exemple, si j'ai un élément HTML comme ceci:

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

Je veux que la partie pertinente de la date est extrait et reconnu:

May,22,2011 

Cela devrait maintenant être converti en objet Java Date régulier.

Mise à jour

Cela devrait fonctionner avec le code HTML de toute page Web, la date peut être contenue dans un élément dans tout format. Par exemple ici sur Stackoverflow le code source ressemble à ceci:

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

Je veux que ce soit fait la façon la plus efficace et je pense que ce serait un sélecteur jQuery ou un filtre qui renvoie une représentation de la date normalisée. Mais je suis ouvert à vos suggestions.

+1

Choisissez un endroit où vous préférez faire le travail (java vs javascript). Nous pouvons le faire dans les deux cas. De plus, savez-vous si certains délimiteurs entoureront toujours le texte (par exemple, au-dessus vous avez "update:" et "view:" autour de la date) – jcolebrand

+2

Vous rencontrerez bien sûr le problème du 10/09/11. 10 septembre 2011 ou 9 octobre 2011? (ou novembre ... ou 1911 ...) –

+0

@drachenstern: non, il peut être très différent chaque fois que je l'analyse. J'ai mis à jour ma question en conséquence - @Jeff B: oui exactement, je dois en quelque sorte reconnaître la plupart de ces motifs – Alp

Répondre

0

je répondrai moi-même parce que je suis venu avec une solution de travail. J'apprécie cependant les commentaires.

/** 
* 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

Étant donné que nous ne pouvons pas nous limiter à un type d'élément spécifique ou aux enfants d'un élément, vous parlez essentiellement de la recherche de dates dans le texte de la page entière. La seule façon de le faire avec n'importe quel type d'efficacité est d'utiliser des expressions régulières. Puisque vous recherchez des dates dans n'importe quel format, vous avez besoin d'une regex pour chaque format acceptable. Une fois que vous définissez ce que ceux-ci sont, simplement compiler les expressions rationnelles et exécuter quelque chose comme:

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])); 
} 

Vous pouvez trouver plus de la date regexes par googler autour, ou les faire vous-même, ils sont assez faciles. Une chose à noter: Vous pourriez probablement combiner quelques expressions rationnelles ci-dessus pour créer un programme plus efficace. Je serais très prudent avec cela, cela pourrait rendre votre code difficile à lire très rapidement. Faire un regex par format de date semble beaucoup plus propre.

0

Vous pouvez envisager d'utiliser getText pour obtenir le texte de l'élément, puis diviser la chaîne, comme -

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

c'est très spécifique et pas généralement applicable – Alp

Questions connexes