网络爬虫 - 跟随链接

5
请耐心等待,我对Python还很陌生 - 但非常开心。我正在尝试编写一个网络爬虫,从最近的丹麦公投结果中爬取数据。我已经成功地从主页提取了所有相关链接。现在我想让Python跟踪这92个链接,并从每个页面收集9个信息。但我卡住了。希望你能给我一点提示。
以下是我的代码:
import requests
import urllib2 
from bs4 import BeautifulSoup

# This is the original url http://www.kmdvalg.dk/

soup = BeautifulSoup(urllib2.urlopen('http://www.kmdvalg.dk/').read())

my_list = []
all_links = soup.find_all("a")

for link in all_links:
    link2 = link["href"]
    my_list.append(link2)

for i in my_list[1:93]:
    print i

# The output shows all the links that I would like to follow and gather information from. How do I do that?

你能详细说明一下每个链接中你想获取的9个信息吗? - titipata
哇 - 你们太棒了!!我需要花点时间来尝试理解你们的解决方案。一旦我理解了它们,我会回来的。非常感谢! - Metods
@titipat:是的。看一下这个子网站。我想获取“stemmeberettigede / 可投票人数”,“Optalte stemmer / 已计票数”,“JA-stemmer / 投赞成票的人数”,“NEJ-stemmer / 投反对票的人数”,“Blanke stemmer / 空白票数”,“Ugyldige stemmer / 无效票数”以及市政府的名称(在这种情况下为Assenskredsen)。 - Metods
哦,我明白了@Metods,我很快会更新我的解决方案。对于lxml,它基本上会遍历每个HTML标记,这可以通过在简单的Web浏览器上进行元素检查找到。/text()将抓取标记内的文本。 - titipata
4个回答

5
这是我的解决方案,使用lxml。它类似于BeautifulSoup
import lxml
from lxml import html
import requests

page = requests.get('http://www.kmdvalg.dk/main')
tree = html.fromstring(page.content)
my_list = tree.xpath('//div[@class="LetterGroup"]//a/@href') # grab all link
print 'Length of all links = ', len(my_list)

my_list 是一个包含所有链接的列表。现在,您可以使用for循环来抓取每个页面内部的信息。

我们可以通过每个链接进行循环。在每个页面内,您可以提取信息作为示例。这仅适用于顶部表格。

table_information = []
for t in my_list:
    page_detail = requests.get(t)
    tree = html.fromstring(page_detail.content)
    table_key = tree.xpath('//td[@class="statusHeader"]/text()')
    table_value = tree.xpath('//td[@class="statusText"]/text()') + tree.xpath('//td[@class="statusText"]/a/text()')
    table_information.append(zip([t]*len(table_key), table_key, table_value))

对于页面下方的表格,
table_information_below = []
for t in my_list:
    page_detail = requests.get(t)
    tree = html.fromstring(page_detail.content)
    l1 = tree.xpath('//tr[@class="tableRowPrimary"]/td[@class="StemmerNu"]/text()')
    l2 = tree.xpath('//tr[@class="tableRowSecondary"]/td[@class="StemmerNu"]/text()')
    table_information_below.append([t]+l1+l2)

希望这能帮到你!

4

一个简单的方法是逐个迭代您的URL列表并单独解析它们:

for url in my_list:
    soup = BeautifulSoup(urllib2.urlopen(url).read())
    # then parse each page individually here

另外,您可以使用Futures显著加速事情进展。

from requests_futures.sessions import FuturesSession

def my_parse_function(html):
    """Use this function to parse each page"""
    soup = BeautifulSoup(html)
    all_paragraphs = soup.find_all('p')
    return all_paragraphs

session = FuturesSession(max_workers=5)
futures = [session.get(url) for url in my_list]

page_results = [my_parse_function(future.result()) for future in results]

这太棒了。感谢您关于迭代我的URL列表的评论,现在我的脚本可以正常工作了。 - Metods
UPS - 没有完成。我相信这个页面上的所有其他建议都更酷 - 但我选择了我能理解的建议。谢谢。这是我的最终代码,它可以工作 - 如果您有使其更智能的建议,请告诉我。来自Methods的最好的问候。 - Metods

2
这是我为您的问题提出的解决方案。
 import requests
from bs4 import BeautifulSoup


def spider():
    url = "http://www.kmdvalg.dk/main"
    source_code = requests.get(url)
    plain_text = source_code.text
    soup = BeautifulSoup(plain_text, 'html.parser')

    for link in soup.findAll('div', {'class': 'LetterGroup'}):
        anc = link.find('a')
        href = anc.get('href')

        print(anc.getText())
        print(href)
        # spider2(href) call a second function from here that is similar to this one(making url = to herf)
        spider2(href)
        print("\n")


def spider2(linktofollow):
    url = linktofollow
    source_code = requests.get(url)
    plain_text = source_code.text
    soup = BeautifulSoup(plain_text, 'html.parser')

    for link in soup.findAll('tr', {'class': 'tableRowPrimary'}):
        anc = link.find('td')

        print(anc.getText())
    print("\n")


spider()

还没有完成...我只从表格中得到了一个简单的元素,但你可以理解它以及它应该如何工作。


在第二个函数中,您可以使用findAll并使用要查找的td类的名称,而不是find('td')。 - CVasquezG

1

这是我最终的代码,运行流畅。如果我可以更聪明地完成它,请告诉我!

import urllib2 
from bs4 import BeautifulSoup
import codecs

f = codecs.open("eu2015valg.txt", "w", encoding="iso-8859-1")

soup = BeautifulSoup(urllib2.urlopen('http://www.kmdvalg.dk/').read())

liste = []

alle_links = soup.find_all("a")

for link in alle_links:
    link2 = link["href"]
    liste.append(link2)

for url in liste[1:93]:
    soup = BeautifulSoup(urllib2.urlopen(url).read().decode('iso-8859-1'))
    tds = soup.findAll('td')
    stemmernu = soup.findAll('td', class_='StemmerNu')
    print >> f, tds[5].string,";",tds[12].string,";",tds[14].string,";",tds[16].string,";", stemmernu[0].string,";",stemmernu[1].string,";",stemmernu[2].string,";",stemmernu[3].string,";",stemmernu[6].string,";",stemmernu[8].string,";",'\r\n'

f.close()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接