V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Shazoo
V2EX  ›  Python

如何优雅的用 scrapy 去抓取连续页面?

  •  
  •   Shazoo · 2016-03-25 14:55:30 +08:00 · 5858 次点击
    这是一个创建于 3164 天前的主题,其中的信息可能已经有所发展或是发生改变。
    举个例子,某个社区的 member 的 profile 页。 url 形如:

    http://abc.com/profile/show?id=1

    id 大概是 1~2000

    这个用 curl 都可以比较轻松的连续抓下来。但是在 scrapy 的框架里面,有点糊涂。

    难道就是修改里面的 start_urls ,弄一个 url 列表吗?


    优雅,给点优雅的方法哈。
    第 1 条附言  ·  2016-03-25 17:10:55 +08:00
    优雅不过是个戏谑词,这都喷……?!

    block 掉果然干净。
    21 条回复    2016-04-01 01:41:26 +08:00
    caizixian
        1
    caizixian  
       2016-03-25 15:12:10 +08:00
    for pagenum in range(1,2000):
    ____yield scrapy.Request("http://abc.com/profile/show?id={}".format(pagenum), callback=self.parse)
    cyberdak
        2
    cyberdak  
       2016-03-25 15:16:36 +08:00
    我想说优雅的毛啊

    去知乎优雅去啊
    Shazoo
        3
    Shazoo  
    OP
       2016-03-25 15:28:59 +08:00
    @caizixian 这样好像和 curl 这种没啥太大区别。
    wizardoz
        4
    wizardoz  
       2016-03-25 16:35:48 +08:00
    有没人看着你的程序是如何跑的,优雅毛啊?
    wizardoz
        5
    wizardoz  
       2016-03-25 16:38:06 +08:00
    用一楼改的,够优雅了吧?

    def scrapGentlyPlease(baseurl):
    ____for pagenum in range(1,2000):
    ________yield scrapy.Request("{}?id={}".format(baseurl,pagenum), callback=self.parse)
    leavic
        6
    leavic  
       2016-03-25 16:39:19 +08:00
    楼主你先给我解释一下什么叫优雅?直接放一个 url_list 这么简单的东西怎么就不优雅了?放个屁都要考虑音高吗?
    Magic347
        7
    Magic347  
       2016-03-25 17:07:57 +08:00   ❤️ 1
    去页面里解析翻取下一页的 link ,然后递归调用 parse 方法即可:

    def parse(self, response):
    ____# parse the page and yield items
    ____next_page = response.xpath("some link element for the next page")
    ____if next_page is not None:
    ________url_next_page = next_page.get_url()
    ________yield scrapy.Request(url_next_page, self.parse)
    Magic347
        8
    Magic347  
       2016-03-25 17:11:25 +08:00   ❤️ 1
    此时 start_urls 初始化为列表页的首页 url 即可,
    不必关心总页数到底有多少,该写法比较通用
    knightdf
        9
    knightdf  
       2016-03-25 17:47:34 +08:00
    告诉你,直接放 start_urls 是最优雅的
    sunchen
        10
    sunchen  
       2016-03-25 18:27:49 +08:00
    def start_requests():
    for i in xrange(2000):
    yield Request('http://abc.com/profile/show?id={}'.format(i))
    ming2281
        11
    ming2281  
       2016-03-25 19:53:47 +08:00 via Android
    下一页一般是 ajax
    到浏览器中看需要 post 哪些参数

    如果页面有规律,那么本页有可能携带了下一页的信息,用 bs 提取出来
    Andy1999
        12
    Andy1999  
       2016-03-25 20:07:26 +08:00 via iPhone
    没 Get 到喷点的只有我一个人么,楼上的都吃炸药了么
    ElegantOfKing
        13
    ElegantOfKing  
       2016-03-25 21:11:42 +08:00
    @Andy1999
    明明一个 range+页数就能搞定的东西,要什么优雅
    billgreen1
        14
    billgreen1  
       2016-03-25 21:24:47 +08:00
    @leavic 你怎么知道 url 后面的 page number 有 2000 个? 如果只有 10 个,你是不是要 request 2000 次?

    我定义的优雅的方式是不需要要自己手动去生成 page number, 最好能通过某种手段自动得到。比如你 request 一下 baseurl 的时候,要是能返回 total page number 就最好了。

    我能想到的不优雅的方式是:
    for page_number in xrange(1, a_large_number):
    ____try:
    ________request("{base_url}{page_number}".format(base_url=base_url, page_number=parge_number)
    ____except ExceptionIDontKnow:
    break

    就是设置一个比较大的 page number, 当访问不到的时候应该会返回一个特定的异常,然后就退出循环
    leavic
        15
    leavic  
       2016-03-26 01:11:40 +08:00
    @billgreen1 我怀疑你都没用过 scrapy , scrapy 直接检查 response.status == 404 就可以判断页面是否存在了,就算不检查, 404 错误根本不会爆 exception , scrapy 自己就会跳过去了。

    不要问我怎么知道的,我今天刚从一个网站爬了 9 万张图片,地址就是我用 range 猜测出来的,在办公室耗时 1.5 个小时爬完。

    至于什么检查一下 baseurl 就可以知道有多少 page number ,如果人家网站有这种 API 给你当然最好,问题是我还没见过哪个网站对爬虫这么友好的,纯粹给服务器找虐啊。

    至于你这段代码,你怎么知道 ID=n 不存在滞后, ID=n+1 就不存在了呢,这么早 break 真的好?而且这个 ID 范围与连续性的问题楼主在问题里并没有提出,完全是你担心的结果,楼主自己都说了它用 curl 都可以抓下来了。


    =============

    至于那些整天高调的喊着 block 掉谁谁谁的人,嗯,欢迎鸵鸟星难民。
    leavic
        16
    leavic  
       2016-03-26 01:18:53 +08:00
    反正楼主看不到我就多说两句,不是大家有多讨厌优雅这两个字,而是写代码这东西到底什么算优雅什么算不优雅本身就是个没有标准的东西。不涉及到代码哲学而只是实现方法的话,更是很难摊上优雅不优雅。
    楼主提出的这种简单至极的问题,就像 1+1=2 一样还去考虑什么优雅,那么首先你得先告诉我什么叫不优雅。
    ====================
    简单点说,如果楼主是甲方,给你提出这个问题要求你优雅的解决,你 tm 不得跳起来问问他什么叫不优雅? start urls 怎么就不优雅了?
    bear330
        17
    bear330  
       2016-03-26 01:32:37 +08:00
    我覺得重點在於樓主用錯了詞, 如果他不要用優雅而用"彈性"來說明需求, 就不會有這麼多爭議
    但他自己知道他要的優雅=彈性嗎? 沒有, 他只是抓一個"感覺", 所以用優雅這個曖昧的詞
    他就像一般的客戶一樣, 其實壓根不知道自己想要的是什麼
    yangqi
        18
    yangqi  
       2016-03-26 01:32:57 +08:00
    很简单,楼主只需要翘起小指,这样不管写什么代码都会很优雅了。
    v2014
        19
    v2014  
       2016-03-26 06:29:12 +08:00
    好好看看 Link Extractors
    lebowsk1s
        20
    lebowsk1s  
       2016-03-29 10:40:11 +08:00
    都给逼乎带坏了,整天优雅优雅,问你什么叫优雅又讲不出个所以然
    Jackhuang
        21
    Jackhuang  
       2016-04-01 01:41:26 +08:00 via Android
    看见楼主题目其实有点想问一个问题, scrapy 是异步的,但是有时候任务好像是同步阻塞的,应该怎么优雅?比如前几天抓知乎是这么设计的,列表得到问题 url ,然后放到池子里,具体一个问题下面有很多答案,我觉得这个时候应该同步把这个问题下面的所有答案得到。然后 yield 一个问题 item 。不知道对不对?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2194 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 00:54 · PVG 08:54 · LAX 16:54 · JFK 19:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.