Python爬虫框架Scrapy中操作make_requests_from_url遇到的坑

遇到个比较奇葩的问题,这两天做个小采集测试,然后用了下 scrapy。 以前只拿这玩意儿的成品二次改过,重新从开头弄感觉有点头大,遇到一些细节问题不好解决。 比如下面,我运行到这行就没下文了,后面的代码并没有执行:

items.extend([self.make_requests_from_url(url).replace(callback=self.parse) for url in validurls])

按理说这里就给爬虫返回请求而已,后面应该是能继续执行的。 validurls 实测是有数据的,不知道这里出了啥毛病,总的局部代码如下:

class DSpider(CrawlSpider):
    #继承自 CrawlSpider,实现自动爬取的爬虫。
name = 'DSpider'

download_delay = 1
start_urls = ['http://www.baidu.com']

def parse(self, response):
    hxs = HtmlXPathSelector(response)
    items = []
    newurls = hxs.select('//a/@href').extract()  
    validurls = []  
    for url in newurls:
        validurls.append(url)
    items.extend([self.make_requests_from_url(url).replace(callback=self.parse) for url in validurls])
    sites = hxs.select('//html')
    for site in sites:
        item = DomainspiderItem()
        item['title'] = site.select('a/text()').extract()
        item['link'] = site.select('a/@href').extract()
        item['desc'] = site.select('text()').extract()
        items.append(item)
    return items

个人觉得 make_requests_from_url 把请求返回后,应该是能直接执行下去的。

网上找了些参考资料:

https://github.com/qz267/ITP/blob/1f8cdfc104e2ed5c2e7a479ef103ac9511e2891c/blog_crawl/blog_crawl/spiders/mindhacks_spider.py

https://www.douban.com/note/287386156/

https://segmentfault.com/q/1010000002556752

大佬们麻烦给点指正意见,批评和友善喷没关系。 不然我这儿一头雾水,小问题耽误不少时间就很糟糕了。。 在线等,感谢!


Python爬虫框架Scrapy中操作make_requests_from_url遇到的坑

6 回复

1.crawl spider 是和 rule 搭配使用的
2.使用使用一般的 spider 就可以了
3.不要自己写一些魔性的方法和方式,该 yield request 就弄 request,该 yield item 就 yield item

想学 scrapy,博客参考:
http://brucedone.com/archives/771

代码参考:
https://github.com/BruceDone/scrapy_demo


在Scrapy里用make_requests_from_url确实容易踩坑。这方法在Spider类里,用来把URL字符串转成Request对象。主要问题出在它默认只生成GET请求,而且不会自动带上爬虫的默认请求头、cookies这些设置。

最常见的情况是在重写start_requests方法时直接用了它。比如你想爬的网站必须用POST请求,或者要带特定Header,这时候光靠make_requests_from_url就不行了。

看个具体的例子。假设你要爬一个需要POST登录的网站:

import scrapy

class MySpider(scrapy.Spider):
    name = 'my_spider'
    start_urls = ['http://example.com/login']
    
    def start_requests(self):
        # 错误示范:这样生成的是GET请求
        # for url in self.start_urls:
        #     yield self.make_requests_from_url(url)
        
        # 正确做法:手动创建POST请求
        for url in self.start_urls:
            yield scrapy.FormRequest(
                url=url,
                formdata={'username': 'user', 'password': 'pass'},
                callback=self.after_login
            )
    
    def after_login(self, response):
        # 登录后的处理
        pass

另一个坑是URL编码问题。如果URL里带中文或特殊字符,make_requests_from_url可能不会帮你正确处理。这时候最好用scrapy.Request直接构造,或者先用urllib.parse.quote处理一下URL。

from urllib.parse import quote
import scrapy

class MySpider(scrapy.Spider):
    name = 'my_spider'
    
    def start_requests(self):
        raw_url = 'http://example.com/search?q=中文关键词'
        # 先编码再创建请求
        encoded_url = quote(raw_url, safe=':/?&=')
        yield scrapy.Request(url=encoded_url)

总之,make_requests_from_url只适合最简单的GET请求场景。稍微复杂点的需求,还是直接用scrapy.Requestscrapy.FormRequest更靠谱,这样能完全控制请求方法、头部、cookies等所有参数。

简单说,复杂请求就别用make_requests_from_url了,直接构造Request对象更省事。

活捉大鱼,哈哈哈

这位兄弟也是群里的?

当然啦,咱们出现在好多个群里

没,rule 原来有的,这里没需要所以去了。因为继承 BaseSpider 老给我报错,比较烦就直接用这个了。
另外,话说这地方大佬看出来还有啥问题么?

回到顶部