刮擦并将输出写入文本文件

pb_*_*_ng 3 python beautifulsoup python-2.7

我使用Python 2.7编写了这个刮刀,从TrueLocal.com.au的前3页获取链接,并将它们写入文本文件.

当我运行程序时,只有第一个链接写在文本文件中.我可以做什么,以便返回的所有URL都写在文件上?

import requests
from bs4 import BeautifulSoup

def tru_crawler(max_pages):
    page = 1
    while page <= max_pages:
        url = 'http://www.truelocal.com.au/find/car-rental/' + str(page)
        code = requests.get(url)
        text = code.text
        soup = BeautifulSoup(text)
        for link in soup.findAll('a', {'class':'name'}):
            href = 'http://www.truelocal.com.au' + link.get('href')
            fob = open('c:/test/true.txt', 'w')
            fob.write(href + '\n')
            fob.close()
            print (href)
        page += 1

#Run the function
tru_crawler(3)
Run Code Online (Sandbox Code Playgroud)

tza*_*man 6

您的问题是,对于每个链接,您打开输出文件,写入,然后再次关闭该文件.这不仅效率低,而且除非您每次以"追加"模式打开文件,否则它将被覆盖.实际上发生的事情是最后一个链接留在文件中,之前的所有内容都丢失了.

快速解决将是改变开放模式'w''a',但它会是更好的小幅调整你的计划.现在,该tru_crawler功能负责抓取您的网站和编写输出; 相反,更好的做法是让每个功能只负责一件事.

您可以将爬网功能转换为一次生成一个链接的生成器,然后将生成的输出分别写入文件.将这fob三行替换为:

    yield href + '\n'
Run Code Online (Sandbox Code Playgroud)

然后,您可以执行以下操作:

lines = tru_crawler(3)
filename = 'c:/test/true.txt'
with open(filename, 'w') as handle:
    handle.writelines(lines)
Run Code Online (Sandbox Code Playgroud)

还要注意使用with statement; 打开文件使用with一旦该块结束就自动关闭它,从而使您不必close()自己打电话.


将生成器和任务分离的思想更进一步,您可能会注意到该tru_crawler函数负责生成要爬网的URL列表.如果您的抓取工具接受可迭代的URL而不是自己创建URL,那么也可以分离出来.就像是:

def make_urls(base_url, pages):
    for page in range(1, pages+1):
        yield base_url + str(page)

def crawler(urls):
    for url in urls:
        #fetch, parse, and yield hrefs
Run Code Online (Sandbox Code Playgroud)

然后,而不是呼叫tru_crawler(3),它变成:

urls = make_urls('http://www.truelocal.com.au/find/car_rental/', 3)
lines = crawler(urls)
Run Code Online (Sandbox Code Playgroud)

然后按上述步骤进行.

现在,如果您想要抓取其他网站,您只需更改您的make_urls呼叫,或为其他网址模式创建不同的生成器,其余代码无需更改!