Python-使用ID提取链接

Python-使用ID提取链接,python,xpath,beautifulsoup,lxml,Python,Xpath,Beautifulsoup,Lxml,我正在学习Python——通过尝试刮取数据来获得漂亮的汤。我有一个HTML页面与此格式 span id listing-name-1 span class address span preferredcontact="1" a ID websiteLink1 span id listing-name-2 span class address span preferredcontact="2" a ID websiteLink2 span id listing-name-3 span clas

我正在学习Python——通过尝试刮取数据来获得漂亮的汤。我有一个HTML页面与此格式

span id listing-name-1
span class address
span preferredcontact="1"
a ID websiteLink1

span id listing-name-2
span class address
span preferredcontact="2"
a ID websiteLink2

span id listing-name-3
span class address
span preferredcontact="3"
a ID websiteLink3
等等,多达40个这样的条目

我希望这些类/ID中的文本的顺序与HTML页面上的顺序相同

首先,我尝试了类似这样的方法来获得清单-name-1

import urllib2
from BeautifulSoup import BeautifulSoup

page = urllib2.urlopen("http://www.yellowpages.com.au/search/listings?clue=architects&locationClue=New+South+Wales&x=45&y=12")

soup = BeautifulSoup(page)

soup.find(span,attrs={"id=listing-name-1"})
它抛出一个现有连接被远程主机强制关闭的错误

我不知道如何解决这个问题。我需要两件事的帮助:

  • 如何修复该错误
  • 如何从1迭代到40?我不想为所有40个span id键入
    soup.find(span,attrs={“id=listing-name-1”})

  • 谢谢大家!

    第二部分的答案很简单:

    import urllib2
    from BeautifulSoup import BeautifulSoup
    
    page = urllib2.urlopen("http://www.yellowpages.com.au/search/listings?clue=architects&locationClue=New+South+Wales&x=45&y=12")
    
    soup = BeautifulSoup(page)
    
    for num in range(1, 41):
        soup.find("span", attrs={"id": "listing-name-"+str(num)})
    

    您的第一个问题似乎与python无关。尝试打印
    page.read()
    ,看看是否有输出。尝试用webbrowser打开页面,看看是否加载

    至于第二个问题,您可以将正则表达式传递给
    findAll

    import re
    import urllib2
    
    from BeautifulSoup import BeautifulSoup
    
    page = urllib2.urlopen("http://www.yellowpages.com.au/search/listings?clue=architects&locationClue=New+South+Wales&x=45&y=12")
    
    soup = BeautifulSoup(page)
    
    listing_names = re.compile('listing-name-[0-9]+')
    listings = soup.findAll('span', id=listing_names)
    print(listings)
    

    上面列出了我机器上的所有列表,因此您的第一个问题肯定不在代码范围内。

    使用
    lxml.html
    您可以直接使用url调用
    parse
    ,这样您就不必自己调用
    urllib
    。另外,您不需要使用
    find
    findall
    而需要调用
    xpath
    ,这样您就可以得到;如果尝试使用
    find
    调用下面的同一表达式,它将返回
    无效谓词
    错误

    #!/usr/bin/env python
    
    import lxml.html
    
    url = "http://www.yellowpages.com.au/search/listings?clue=architects&locationClue=New+South+Wales&x=45&y=12"
    tree = lxml.html.parse(url)
    listings = tree.xpath("//span[contains(@id,'listing-name-')]/text()")
    print listings
    
    将输出此内容,并保留顺序:

    ['Cape Cod Australia Pty Ltd',
    'BHI',
    'Fibrent Pty Ltd Building & Engineering Assessments',
     ...
    'Archicentre']
    
    要回答您对我的答案的评论中的问题,您要搜索的是
    ,其中包含您想要的所有信息。(姓名、地址等)。然后,您可以在符合这些条件的div元素列表上循环,并使用xpath表达式提取其余信息。请注意,在本例中,我使用了
    container.xpath('.//span')
    ,它将从当前节点(container div)进行搜索,否则,如果省略
    ,只使用
    //span
    ,它将从树的顶部开始搜索,您将得到匹配的所有元素的列表,选择容器节点后,这不是您想要的

    #!/usr/bin/env python
    
    import lxml.html
    
    url = "http://www.yellowpages.com.au/search/listings?clue=architects&locationClue=New+South+Wales&x=45&y=12"
    tree = lxml.html.parse(url)
    container = tree.xpath("//div[@class='listingInfoContainer']")
    listings = []
    for c in container:
        data = {}
        data['name'] = c.xpath('.//span[contains(@id,"listing")]/text()')
        data['address'] = c.xpath('.//span[@class="address"]/text()')
        listings.append(data)
    
    print listings
    
    哪些产出:

    [{'name': ['Cape Cod Australia Pty Ltd'], 
      'address': ['4th Floor 410 Church St, North Parramatta NSW 2151']}, 
     {'name': ['BHI'], 
      'address': ['Suite 5, 65 Doody St, Alexandria NSW 2015']}, 
     {'name': ['Fibrent Pty Ltd Building & Engineering Assessments'], 
      'address': ["Suite 3B, Level 1, 72 O'Riordan St, Alexandria NSW 2015"]}, 
      ...
     {'name': ['Archicentre'], 
      'address': ['\n                                         Level 3, 60 Collins St\n                                         ',
                  '\n                                         Melbourne VIC 3000\n                                    ']}]
    
    这是一个字典列表(同样,以您想要的方式保持顺序),其中包含键
    name
    address
    ,每个键都包含一个列表。最后的列表由
    text()
    返回,它在原始html中保留
    \n
    换行符,并将

    之类的内容转换为新的列表元素。其原因的一个示例是列表项Archicenter,其中原始HTML表示为:

    <span class="address">
         Level 3, 60 Collins St
         <br/>
         Melbourne VIC 3000
    </span>
    
    
    科林斯街60号3楼
    
    墨尔本维多利亚3000
    尝试
    page.read()
    并查看您是否能够检索页面内容我将首先将页面下载到本地计算机,然后计算解析部分,最后如果准备好了,插入远程文件读取…Lattyware,谢谢!它仍然向我抛出相同的错误:错误:[Errno 10054]远程主机强制关闭了一个现有连接`从
    回溯开始的回溯(最近一次调用):文件“F:\Documents and Settings\Bhavani\Desktop\YP.py”,第6行,在soup=beautifulsou(page)
    @BhavaniKannan我运行了这个程序,效果很好,所以你的环境一定有问题。厕所,再次感谢!我真的不知道为什么,但当lxml解决方案运行良好时,这仍然会给我带来那个错误。也许,你能告诉我在我的环境中应该检查什么吗?我在WindowsXPSP2上使用Python2.7(空闲),我刚刚尝试在page.read()之前添加time.sleep(2)。还是不走运。老实说,我一点线索都没有——也许值得单独问一个问题。Rob,我的web浏览器(Firefox)加载的页面很好,但是page.read()会抛出一个错误。我应该做什么?提取链接的语法是什么?我试图模仿你的语法,比如
    Website=tree.xpath(//a[contains(@id,'websiteLink')]/href()”
    ,但它不起作用。另外,我刚刚发现语法
    Address=tree.xpath(//span[contains(@class,'Address')]/text())
    只需从带有
    @BhavaniKannan的页面中获取所有内容,我更新了我的答案,以解决您在评论中提出的问题。我回答了我认为更重要的问题,你正试图通过你的问题来解决。有很多不同的方法来解决这个问题,但我认为这是一个好方法,简单的方法,让您选择您关心的HTML文档子集,然后从每个重复部分提取您关心的特定数据。@BhavaniKannan在选择包含地址的span时,我使用了更简单的xpath表达式
    //span[@class='address']
    ,而不是
    //span[contains](@class,'address')]
    ,因为在本例中,我知道我想精确匹配名为
    'address'
    的类,而在另一个示例中,我试图匹配
    'listing-name-1','listing-name-2',等
    ,因此我使用了
    包含(@id,'listing-name-'))
    函数来匹配子字符串;严格来说,我应该使用'starts with(@id,'listing name-')。除非你真的需要它,否则没有理由使用字符串函数。真不敢相信你花了这么多精力来写下它来解释事情。真是太神奇了……除非我能把它提高100000000次。非常感谢!