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

Javascript 正则表达式:如何从字符串中获取时间,javascript,jquery,html,regex,cheerio,Javascript,Jquery,Html,Regex,Cheerio,我正在为一个JS项目开发一个scraper,我的正则表达式fu可能会比现在更好 给定一个数据结构,如 <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> <

我正在为一个JS项目开发一个scraper,我的正则表达式fu可能会比现在更好

给定一个数据结构,如

<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>
正如你所看到的,我很难从上面的结构中找到时间

通常,在与特定节目相对应的
li
结尾会有一点纯文本,因此

  • 山脚,S.F.马特·庞德,宾夕法尼亚州,灯塔和捕鲸船,凯尔·M·特里齐a/a$14/$16,晚上8点/9点**
  • 我会寻找抓取“8pm/9pm”的文字了

    <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 **
    
  • ,a/a$14/$16晚上8点/9点**
  • 有时是“8pm”,有时是“8pm/9m”,有时根本不存在


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

    不要正则表达式完整的原始html(一般建议)

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

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

    PS,刮刀上的一句话:通常只有在你完全成功地完成刮刀后,你才知道你的最后一个动作!(就像你通常在最后一次寻找时发现丢失的东西一样)。
    正如Tomalak所评论的:陷阱1:与您预期不匹配的数据。尝试研究您预期的数据格式

    编辑:
    额外建议:添加尽可能多的错误检查。尝试将测试期间发现的每个缺陷转化为检查。一旦开始清理大量数据,您需要任何可以得到的帮助

    考虑一种分块方法:如果检查失败,您不需要从数据的开头重新开始。相反,添加额外的检查/解决方案并继续您的刮取。

    否则,仅仅测试/调试你的scraper甚至可能看起来像DOS行为/流量。

    让它工作起来,下面是我最终使用的代码

    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
    
                )
    
    
            )
    
    )
    

    通过查看您链接到的页面,时间格式比您在此处描述的要多。第一步,请详细列出您希望使用的每种输入格式,以及您希望从每种格式中检索的值。不要正则化完整的原始html(一般建议)。相反,尝试将html加载到临时容器div(或
    documentFragment
    ,但您需要一些自定义的基本getter垫片)。现在以您的方式(循环)遍历已知的结构,放弃所有不需要的内容(如锚定),最后循环遍历容器以获取最终数据(使用更简单的正则表达式,匹配
    /(\d+[ap]m/?){1,2}$/i
    (正如Tomalak所说,我认为您已经研究了预期的格式).PS,刮刀的话:只有当你完全成功地完成刮刀后,你才知道你的最后一个动作。谢谢,这非常有用。欢迎你!我把它作为你考虑的答案。太棒了,谢谢——有什么关于垫片库/示例的建议吗?没有,对不起。每个刮刀都是定制的。不过,这里有一个非常好的刮刀呃,我最近做了(该电台现在关闭了):从2013年12月8日开始的完整h4xed播放列表(现在生成更多统计数据并具有基本的文件大小估计例程):(此播放列表是用更新的刮板刮取的:)(PS:Andy知道,我共享了它以帮助拯救现在已死亡的电台的播放列表)这可能是一个更好的解决方案(提示)并涵盖了最基本的需求(但不是作为图书馆)。
    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
    
                )
    
    
            )
    
    )