正则表达式:如何从字符串中获取时间

时间:2014-05-23 02:15:58

标签: javascript jquery html regex cheerio

我正在研究The List作为JS项目的刮刀,我的正则表达式可能比现在更好。

给定像

这样的数据结构
<a name="may_21"><b>Wed May 21</b></a>
<ul>
<li><b><a href="by-club.0.html#Ace_of_Spades__Sacramento">Ace of Spades, Sacramento</a></b> <a href="by-band.0.html#Christina_Perri">Christina Perri</a>, <a href="by-band.0.html#Birdy">Birdy</a> a/a $20 7pm **
...
</ul>

我写了以下内容以利用cheerio来获取日期,地点和乐队列表:

request(url, (error, response, html)->
    if(!error)
        $ = cheerio.load(html)

        concert = { bands : {}, location : {venue: "", address : ""}, date: {date: "", time: ""}}

        calendar = {}

        dates = []

        #grab dates
        $('body > ul > li > a').each(->
            data = $(this)
            $dates = data.children().first()
            dates.push($dates.text())
        )

        #build concerts
        for date in dates
            $("a:contains('" + date + "')").siblings().each(->
                $venue = $(this).children().find("b")
                $bands = $venue.siblings("a")
                $time = $venue.parent()#.match()
            )

)

正如您所看到的,我无法弄清楚如何从上述结构中获取时间。

通常情况下,li末尾会出现一些与特定节目相对应的纯文本,因此对于类似

的内容

  • The Hill of the Hill,S.F。 Matt Pond PA,Lighthouse and the Whaler,Kyle M. Terrizzi a / a $ 14 / $ 16 8 pm / 9pm **
  • 我希望从

    中获取“晚上8点/晚上9点”的文字
    <li><b><a href="by-club.0.html#Bottom_of_the_Hill__S_F_">Bottom of the Hill, S.F.</a></b> <a href="by-band.2.html#Matt_Pond_PA">Matt Pond PA</a>, <a href="by-band.2.html#Lighthouse_And_The_Whaler">Lighthouse And The Whaler</a>, <a href="by-band.1.html#Kyle_M__Terrizzi">Kyle M. Terrizzi</a> a/a $14/$16 8pm/9pm **
    

    有时它会以“晚上8点”的形式出现,有时会是“晚上8点/ 9点”,有时根本不存在。

    构建正则表达式以获取此数据的最佳方法是什么?

    2 个答案:

    答案 0 :(得分:1)

    不要使用完整的原始html(一般建议)。

    相反,尝试将html加载到临时容器div(或documentFragment,但需要一些自定义的基本getter-shims)。

    现在按照已知的结构(循环)工作,丢弃你不需要的所有东西(如锚点),最后循环通过容器(在剩下的东西中)来获取你的最终数据(使用更简单的正则表达式,匹配例如:/(\d+[ap]m/?){1,2}$/i

    PS,来自刮刀的一句话:一旦你完全成功完成你的刮擦,你通常只知道你的最后一个例程! (就像你通常在最后一个地方发现丢失的东西......) 正如Tomalak评论的那样:陷阱1:数据与您预期的不符。尝试研究您期望的数据格式!!

    修改
    额外建议:尽可能多地添加错误检查。尝试将您在测试过程中发现的每个漏洞转换为支票。在您开始抓取大量数据后,您需要可以获得任何帮助。

    考虑一种分块方法:如果检查失败,您不需要从数据的开头重新开始。相反,添加额外的检查/解决方案并继续你的刮 否则只是测试/调试你的刮刀甚至可能看起来像DOS行为/流量。

    答案 1 :(得分:0)

    让这个工作,这是我最终使用的代码

    fs = require('fs')
    request = require('request')
    cheerio = require('cheerio')
    crypto = require("crypto")
    
    url = 'http://www.foopee.com/punk/the-list/by-date.0.html'
    
    getConcertItem = (text, regex)->
        return text.match(regex)?.toString().replace(/,/g, '').trim()
    
    request(url, (error, response, html)->
        if(!error)
            $ = cheerio.load(html)
    
            #print(html)
    
            calendar = {}
    
            $dates = $('body > ul > li')
    
            #dates
            $dates.each(->
    
                date = $(this).find("a").first().text()
    
                $concerts = $(this).children("ul").children()
    
                $concerts.each( ->
    
                    #todo: use the import-style ID generator
                    ID = parseInt(crypto.randomBytes(4).toString('hex'), 16)
    
                    concert = {bands : [], location : {venue: "", address : ""}, date: {date: "", time: ""}, cost: "", allAges: false}
    
                    $venue = $(this).find("b")
                    concert.location.venue = $venue.text()
    
                    concertText = $venue.parent().clone().children().remove().end().text()
    
                    timeRegex = /(\d?:?\d+[ap]m\/?\s?\w*\s?)/g
                    concert.date.date = date
                    concert.date.time = getConcertItem(concertText, timeRegex)
    
                    costRegex = /(\$\d+[\/-]?)/g
                    concert.cost = getConcertItem(concertText, costRegex)
    
                    allAgesRegex = /(a\/a)/g
                    if getConcertItem(concertText, allAgesRegex)
                        concert.allAges = true
    
                    $bands = $venue.siblings()
                    bands = []
                    $bands.each( ->
                        band = $(this).text()
                        bands.push(band)
                    )
                    concert.bands = bands
    
                    calendar[ID] = concert
    
                )
    
    
            )
    
    )