0

我正在为The List作为一个 JS 项目开发一个刮板,而我的 regex-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>

我编写了以下代码来利用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()
            )

)

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

通常,这将是 a 末尾的一些纯文本li,对应于特定的节目,因此对于类似

  • 山底,SF Matt Pond PA,灯塔和捕鲸者,Kyle M. Terrizzi 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 **
    

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

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

    4

    2 回答 2

    1

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

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

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

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

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

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

    于 2014-05-23T02:41:11.143 回答
    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
    
                )
    
    
            )
    
    )
    
    于 2014-05-23T22:18:06.363 回答