【问题标题】:converting scrapy to lxml将scrapy转换为lxml
【发布时间】:2015-06-21 20:20:40
【问题描述】:

我的代码看起来像这样

for row in response.css("div#flexBox_flex_calendar_mainCal table tr.calendar_row"):
    print "================" 
        print row.xpath(".//td[@class='time']/text()").extract()
        print row.xpath(".//td[@class='currency']/text()").extract()
        print row.xpath(".//td[@class='impact']/span/@title").extract()
        print row.xpath(".//td[@class='event']/span/text()").extract()
        print row.xpath(".//td[@class='actual']/text()").extract()
        print row.xpath(".//td[@class='forecast']/text()").extract()
        print row.xpath(".//td[@class='previous']/text()").extract()
    print "================" 

我可以像这样使用纯 python 获得相同的东西,

from lxml import html
import requests

page = requests.get('http://www.forexfactory.com/calendar.php?day=dec1.2011')

tree = html.fromstring(page.text)

print tree.xpath(".//td[@class='time']/text()")
print tree.xpath(".//td[@class='currency']/text()")
print tree.xpath(".//td[@class='impact']/span/@title")
print tree.xpath(".//td[@class='event']/span/text()")
print tree.xpath(".//td[@class='actual']/text()")
print tree.xpath(".//td[@class='forecast']/text()")
print tree.xpath(".//td[@class='previous']/text()")

但是我需要逐行执行此操作。我第一次尝试移植到 lxml 不起作用:

from lxml import html
import requests

page = requests.get('http://www.forexfactory.com/calendar.php?day=dec1.2011')

tree = html.fromstring(page.text)

for row in tree.css("div#flexBox_flex_calendar_mainCal table tr.calendar_row"):
    print row.xpath(".//td[@class='time']/text()")
    print row.xpath(".//td[@class='currency']/text()")
    print row.xpath(".//td[@class='impact']/span/@title")
    print row.xpath(".//td[@class='event']/span/text()")
    print row.xpath(".//td[@class='actual']/text()")
    print row.xpath(".//td[@class='forecast']/text()")
    print row.xpath(".//td[@class='previous']/text()")

将这个scrapy代码移植到纯lxml的正确方法是什么?

编辑:我已经接近了一点。我可以看到一个table{} 对象,我只是不知道怎么走路。

import urllib2
from lxml import etree


#import requests

def wgetUrl(target):
    try:
        req = urllib2.Request(target)
        req.add_header('User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3 Gecko/2008092417 Firefox/3.0.3')
        response = urllib2.urlopen(req)
        outtxt = response.read()
        response.close()
    except:
        return ''

    return outtxt


url = 'http://www.forexfactory.com/calendar.php?day='
date = 'dec1.2011'

data = wgetUrl(url + date)
parser = etree.HTMLParser()

tree   = etree.fromstring(data, parser)

for elem in tree.xpath("//div[@id='flexBox_flex_calendar_mainCal']"):
    print elem[0].tag, elem[0].attrib, elem[0].text
    # elem[1] is where the table is
    print elem[1].tag, elem[1].attrib, elem[1].text
    print elem[1]

【问题讨论】:

    标签: python scrapy lxml


    【解决方案1】:

    我喜欢使用lxml 进行抓取。我通常不使用它的xpath 功能,而是选择他们的ElementPath 库。它在语法上非常相似。以下是我将如何移植您的 scrapy 代码。

    逐行进行:

    初始化:

    from lxml import etree
    
    # analogous function xpath(.../text()).extract() for lxml etree nodes
    def extract_text(elem):        
        if elem is None:
            print None
        else
            return ''.join(i for i in elem.itertext())
    
    data = wgetUrl(url+date)  # wgetUrl, url, date you defined in your question
    tree = etree.HTML(content)
    

    第 1 行

    # original
    for row in response.css("div#flexBox_flex_calendar_mainCal table tr.calendar_row"):
    
    # ported
    for row in tree.findall(r'.//div[@id="flexBox_flex_calendar_mainCal"]//table/tr[@class="calendar_row"]'):
    

    第 2 行

    print "================" 
    

    第 3 行

    # original
    print row.xpath(".//td[@class='time']/text()").extract()
    # ported
    print extract_text(row.find(r'.//td[@class="time"]'))
    

    第 4 行

    # original
    print row.xpath(".//td[@class='currency']/text()").extract()
    # ported
    print extract_text(row.find(r'.//td[@class="currency"]'))
    

    第 5 行

    # original
    print row.xpath(".//td[@class='impact']/span/@title").extract()
    # ported
    td = row.find(r'.//td[@class="impact"]/span')
    if td is not None and 'title' in td.attrib:
        print td.attrib['title']
    

    第 6 行

    # original
    print row.xpath(".//td[@class='event']/span/text()").extract()
    # ported
    print extract_text(row.find(r'.//td[@class="event"]/span'))
    

    第 7 行

    # original
    print row.xpath(".//td[@class='actual']/text()").extract()
    # ported
    print extract_text(row.find(r'.//td[@class="actual"]'))
    

    第 8 行

    # original
    print row.xpath(".//td[@class='forecast']/text()").extract()
    # ported
    print extract_text(row.find(r'.//td[@class="forecast"]'))
    

    第 9 行

    # original
    print row.xpath(".//td[@class='previous']/text()").extract()
    # ported
    print extract_text(row.find(r'.//td[@class="previous"]'))
    

    第 10 行

    print "================" 
    

    现在大家一起:

    from lxml import etree
    
    def wgetUrl(target):
        # same as you defined it
    
    # analogous function xpath(.../text()).extract() for lxml etree nodes
    def extract_text(elem):        
        if elem is None:
            print None
        else
            return ''.join(i for i in elem.itertext())
    
    content = wgetUrl(your_url)  # wgetUrl as the function you defined in your question
    node = etree.HTML(content)
    
    
    for row in node.findall(r'.//div[@id="flexBox_flex_calendar_mainCal"]//table/tr[@class="calendar_row"]'):
        print "================" 
        print extract_text(row.find(r'.//td[@class="time"]'))
        print extract_text(row.find(r'.//td[@class="currency"]'))
        td = row.find(r'.//td[@class="impact"]/span')
        if td is not None and 'title' in td.attrib:
            print td.attrib['title']
        print extract_text(row.find(r'.//td[@class="event"]/span'))
        print extract_text(row.find(r'.//td[@class="actual"]'))
        print extract_text(row.find(r'.//td[@class="forecast"]'))
        print extract_text(row.find(r'.//td[@class="previous"]'))
        print "================"
    

    【讨论】:

    • 感谢农夫乔。我想我很清楚如何从您的示例中转到从 scrapylxml。
    • 有没有办法说 node.findall(r'.//div[@id="flexBox_flex_calendar_mainCal"]//table/tr[@class="calendar*"]') 这样它匹配 any 以 "calendar" 开头的行?
    • @Ivan 我不确定是否有原生解决方案的想法,但您可以拥有:nodes = node.findall(r'.//div[@id="flexBox_flex_calendar_mainCal"]//table/tr[@class]')。这将为您提供具有class 属性的所有tr 节点,然后您可以自己过滤它:calendar_nodes = [ node for node in nodes if node.attrib['class'].startswith('calendar') ]
    • 该建议会导致正确的解决方案。谢谢农夫乔。
    猜你喜欢
    • 2013-07-25
    • 1970-01-01
    • 2012-02-08
    • 2019-11-17
    • 1970-01-01
    • 2011-03-11
    • 2023-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多