【问题标题】:Scraper collecting the content of first page only只收集首页内容的爬虫
【发布时间】:2018-04-09 20:48:36
【问题描述】:

我使用 python 编写了一个刮板,用于从 yiffy 种子中刮取电影名称。该网页已遍历大约 12 页。如果我使用print 语句运行我的爬虫,它会给我所有页面的所有结果。但是,当我使用return 运行相同的内容时,它只会给我第一页的内容,而不是继续到下一页来处理其余部分。由于我很难理解 return 语句的行为,如果有人指出我哪里出错并给我一个解决方法,我会很高兴。提前致谢。

这就是我正在尝试的(完整代码):

import requests
from urllib.request import urljoin
from lxml.html import fromstring            

main_link = "https://www.yify-torrent.org/search/western/"

# film_storage = [] #I tried like this as well (keeping the list storage outside the function)

def get_links(link):
    root = fromstring(requests.get(link).text)
    film_storage = []
    for item in root.cssselect(".mv"):
        name = item.cssselect("h3 a")[0].text
        film_storage.append(name)
    return film_storage

    next_page = root.cssselect(".pager a:contains('Next')")[0].attrib['href'] if root.cssselect(".pager a:contains('Next')") else ""
    if next_page:
        full_link = urljoin(link,next_page)
        get_links(full_link)

if __name__ == '__main__':  
    items = get_links(main_link)
    for item in items:
        print(item)

但是,当我喜欢下面的内容时,我会得到所有结果(仅限粘贴的要点部分):

def get_links(link):
    root = fromstring(requests.get(link).text)
    for item in root.cssselect(".mv"):
        name = item.cssselect("h3 a")[0].text
        print(name)            ## using print i get all the results from all the pages

    next_page = root.cssselect(".pager a:contains('Next')")[0].attrib['href'] if root.cssselect(".pager a:contains('Next')") else ""
    if next_page:
        full_link = urljoin(link,next_page)
        get_links(full_link)

【问题讨论】:

    标签: python python-3.x web-scraping return


    【解决方案1】:

    您的 return 语句过早地终止了您的 get_links() 函数。这部分的意思

    next_page = root.cssselect(".pager a:contains('Next')")[0].attrib['href'] if root.cssselect(".pager a:contains('Next')") else ""
        if next_page:
            full_link = urljoin(link,next_page)
            get_links(full_link)
    

    永远不会被执行。

    Quickfix 是将 return 语句放在函数的末尾,但你必须将 film_storage 设为全局(在 get_links() 函数之外定义)。

    编辑: 刚刚意识到,由于您将使您的film_storage 全球化,因此不需要return 语句。

    main 中的代码如下所示:

    get_links(main_link)
    for item in film_storage:
        print(item)
    

    【讨论】:

    • 这似乎很有希望。试一试,让你知道。谢谢。
    • 顺便说一句,这只是一个快速修复解决方案,因为您提到您刚刚开始您的抓取之旅。但我建议您以后尝试@randomir 的解决方案/建议。这样,您就可以制作更好、更高效的刮板。
    • 对不起,刚刚意识到,由于film_storage是全局的,所以不需要return语句。
    • 您的解决方案完美运行。基本上,我在这里粘贴的是我完整代码的一小部分,应该由一个类重用。再次感谢。
    • 您建议的主要语句部分也可以正常工作。顺便说一句,我在主要语句下编写该部分的方式有什么问题?请注意回复。谢谢。
    【解决方案2】:

    您的film_storage 结果列表对于函数get_links() 是本地的,该函数会为下一页递归调用。在递归调用之后(对于所有下一页),初始(入口)函数仅返回第一页的结果。

    您必须 (1) 将尾递归展开到循环中,(2) 使结果列表全局化; (3) 使用回调(就像您调用 print),或者最好的选择 (4) 是get_links 函数转换为生成器,从而为所有页面生成结果。

    生成器版本:

    def get_links(link):
        root = fromstring(requests.get(link).text)
        for item in root.cssselect(".mv"):
            name = item.cssselect("h3 a")[0].text
            yield name
    
        next_page = root.cssselect(".pager a:contains('Next')")[0].attrib['href'] if root.cssselect(".pager a:contains('Next')") else ""
        if next_page:
            full_link = urljoin(link,next_page)
            for name in get_links(full_link):
                yield name
    

    【讨论】:

    • 感谢随机输入。为此 +1。
    • 不客气,但请注意,您应该尽量避免使用全局变量。它们会降低您的代码的可读性,程序的不同部分以意想不到的方式耦合,并且整个程序更容易出错。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多