使用 Pyspider 爬取京东 Wap 版本商品价格 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
imlonghao
17.32D
2.47D
V2EX    程序员

使用 Pyspider 爬取京东 Wap 版本商品价格

  •  
  •   imlonghao
    imlonghao 2014-12-31 20:12:57 +08:00 10209 次点击
    这是一个创建于 3956 天前的主题,其中的信息可能已经有所发展或是发生改变。

    爬虫运行在 @binux 的 Pyspider


    总想找一个站来练习一下写爬虫,于是乎,我找到了京东的Wap版。

    关于京东Wap版

    优点
    1. 没有反爬虫的设置,似乎不限制并发链接
    2. 单个页面大小比较小,对VPS来说节省流量
    3. 链接结构比较整齐,比较容易分析

    缺点
    1. 可以采集的数据比较少,只有商品分类、名称和价格
    2. 单个分类分页最多2000页,但其实不仅仅有2000页

    链接分析

    我们大概的思路就是:全部分类-->二级分类-->三级分类-->遍历全部分页-->采集数据

    打开wap.jd.com后,我们不难就可以看出全部分类的地址:http://wap.jd.com/category/all.html

    然后我们观察链接,二级分类的地址均是以http://wap.jd.com/category/开头的

    三级分类的地址均是以http://wap.jd.com/products/开头的

    然后,我们就可以看到商品列表页了。

    在商品页中,有两类链接我们需要分析。一是商品详细页的地址,以http://wap.jd.com/product/开头;另一个是页面的页数,我们使用Pyspider的分析工具,可以知道页面的页数是HTML>BODY>DIV.page>A[href]里面的。

    知道了上面的信息,我们基本上就可以写代码开始采集了。

    注意

    京东的地址中,会传入一个区别不同用户的cid和sid的值,例如我的就是cid=1323&sid=24faaa1458222af7f13as9kf3aa12337,实际上链接只有.html前面的部分是有用的,.html后面?开始其实都是可以忽略的。

    在Pyspider中,系统是通过url来区别不同的地址的,如果是sid不同的话,会被识别成不同的页面,最后的话可能会造成重复采集的结果。

    因此,我打算使用urlparse模块中的urljoin来处理这些地址,可能方法有点不对,但是还是达到了效

    代码

    请参考我的网站:https://imlonghao.com/Pyspider/wap.jd.com.html

    后记

    使用Pyspider的效率我个人还是满意的,总共大概就是我2天爬了将近500W商品,速度其实可以再进一步,因为我不敢开太大并发因为已经VPS的内存不够..............

    除此之外,硬盘也不够了,记录使用默认的配置,results.db总共占用了2.1G,而tasks.db占用了12G左右

    此外,给@binux 反馈一个问题,像我这样500W数据的话,通过/results/dump/jd.json无法导出数据,显示超时....

    第 1 条附言    2015-01-01 01:21:32 +08:00
    无法导出数据的问题已经解决,系前端与webui单线程等多个原因导致的,目前已经解决。
    需要这500w商品数据进行大数据分析得可以联系我
    35 条回复    2016-02-16 12:30:57 +08:00
    binux
        1
    binux  
       2014-12-31 20:24:23 +08:00   1
    pyspider 前面还有反代吗? pyspider 是流式输出的,虽然打开表很慢,但是应该还是能输出的
    imlonghao
        2
    imlonghao  
    OP
       2014-12-31 20:29:56 +08:00
    @binux 可能是这个的问题吧,前面有nginx和varnish,我试一试直接下载:5000的看看
    imlonghao
        3
    imlonghao  
    OP
       2014-12-31 20:37:02 +08:00
    root@pyspider:~# wget 127.0.0.1:5000/results/dump/jd.json
    --2014-12-31 20:31:43-- http://127.0.0.1:5000/results/dump/jd.json
    Connecting to 127.0.0.1:5000... connected.
    HTTP request sent, awaiting response...

    就这样就不动了,我记得如果是流式输出的话wget不是这样的..
    wangfeng3769
        4
    wangfeng3769  
       2014-12-31 20:40:29 +08:00   1
    想知道你是怎么爬取北京之外的商品情况的 比如天津的情况。
    imlonghao
        5
    imlonghao  
    OP
       2014-12-31 20:44:14 +08:00
    @wangfeng3769 我只是爬了商品的名称、分类以及价格,没有爬有没有货这个..
    wangfeng3769
        6
    wangfeng3769  
       2014-12-31 20:49:28 +08:00
    @imlonghao 这个接口默认是北京的 ,想知道你是怎么做到爬取天津情况的
    imlonghao
        7
    imlonghao  
    OP
       2014-12-31 20:57:11 +08:00
    @wangfeng3769
    我刚刚说了我并没有爬不同地区的商品情况,我的VPS是日本的,所以只能爬了北京的情况。

    不过我还是根据你的需求看了看京东的设计,大概能满足你的有求了。

    商品页:
    天津 > 东丽区 > 全境
    provinceId=3 天津
    cityId=51035 东丽区 | cityId=51042 静海区 | 等等...
    countryId=39620 全境

    其中,countryId默认天津都是全境,不需要另外设置,只需要设置cityID和provinceId即可。

    想要看那个地区的库存情况,爬虫的时候设置不同天津(provinceId=3)地区的cityID即可。

    我所贴的代码:
    self.crawl(urljoin(each.attr.href,'?=').replace('?=',''), callback=self.in_page)

    你要看天津的,就可以改成:
    self.crawl(urljoin(each.attr.href,'?province=3&cityID=51042'), callback=self.in_page)

    等等,其他自己发挥
    binux
        8
    binux  
       2014-12-31 21:04:01 +08:00   1
    @imlonghao 嗯,那确实是个问题。应该是 tornado + Flask 就没法用流了
    imlonghao
        9
    imlonghao  
    OP
       2014-12-31 21:07:09 +08:00
    @binux
    您看看吧。那这样的话要导出数据只能通过db那里来导?打算换去mysql好导出一下..
    另外,我爬京东的时候用35/30这样来爬,算是快么?
    binux
        10
    binux  
       2014-12-31 21:09:34 +08:00
    @imlonghao 非常快
    invite
        11
    invite  
       2014-12-31 23:32:51 +08:00
    有限制的, 前段时间就爬过.
    imlonghao
        12
    imlonghao  
    OP
       2014-12-31 23:35:32 +08:00 via Android
    @invite 那可能我人品好?35页/秒跑了500w商品没封
    invite
        13
    invite  
       2014-12-31 23:43:17 +08:00
    @imlonghao 你可以先看看, 爬出来的结果, 有没有不是你想要的.
    imlonghao
        14
    imlonghao  
    OP
       2014-12-31 23:46:31 +08:00 via Android
    @invite 检查过的了,都是想要的结果,如果返回403之类的不会记录的,现在只是苦于不能优雅地导出数据。
    binux
        15
    binux  
       2015-01-01 00:04:32 +08:00
    @imlonghao 我改过了,试试看
    imlonghao
        16
    imlonghao  
    OP
       2015-01-01 00:15:25 +08:00 via Android
    @binux 看到了,等我把之前的数据导入mysql再试试,待会@ 你
    新年快乐
    lifsth
        17
    lifsth  
       2015-01-01 20:26:50 +08:00
    楼主 服务器 108.61.250.165是否已经失效?
    imlonghao
        18
    imlonghao  
    OP
       2015-01-01 20:53:07 +08:00
    @lifsth 超流量了,关掉了
    benjiam
        19
    benjiam  
       2015-01-02 02:09:00 +08:00
    这个貌似很爽 我3年前玩的时候,512M linode 20分钟抓取50w 产品。那时候京东总共也就50万种产品,价格还是图片要识别。现在有500万种了?
    imlonghao
        20
    imlonghao  
    OP
       2015-01-02 07:36:28 +08:00 via Android
    @benjiam 20分钟50w也是超快的了,我几天才爬了500w,而且还没爬完,你要看数据的话可以发给你
    marksaas
        21
    marksaas  
       2015-01-02 11:12:26 +08:00
    发我一份吧,mark_wk#qq.com,多谢。。
    benjiam
        22
    benjiam  
       2015-01-02 17:35:56 +08:00
    你是拉所有的产品详细情况还是 产品列表吗?

    http://wap.jd.com/products/1315-1343-1354-0-0-0-0-0-0-0-1-1-2.html?cid=1354&sid=e3fd661f50a653203402decbfe71b57e

    这种产品列表吗?如果是产品列表的话,应该非常快

    我简单的计算了一下
    500万产品, 单页大概150K, 每页大概15种产品 gzip 的话 算压缩到0.25

    500.0* 10 * 1024 * 150 * 1024 / 15 / 4 /1024/ 1024/1024
    大概是12G 数据
    imlonghao
        23
    imlonghao  
    OP
       2015-01-02 17:46:57 +08:00 via Android
    @benjiam 只保存了商品名字,价格和分类。最后json格式,只有1.9G,不知道我有没有数错行数,你要的话可以留邮箱拿去看看
    benjiam
        24
    benjiam  
       2015-06-07 23:50:29 +08:00
    貌似已经不能用来 现在默认会跳到m.jd.com
    benjiam
        25
    benjiam  
       2015-06-07 23:56:43 +08:00
    已经破解 很简单
    UnderIndex
        26
    UnderIndex  
       2015-07-27 18:24:30 +08:00
    @benjiam 你遇到过评论重复的情况吗,就是请求太频繁会返回的评论结果是一样的。
    l0wkey
        27
    l0wkey  
       2016-02-15 12:04:21 +08:00
    @binux
    我也遇到无法导出了, wget 的 json 流,数据量是 300w 多一点

    --2016-02-15 11:51:41-- http://127.0.0.1:5000/results/dump/zhi.json
    Connecting to 127.0.0.1:5000... connected.
    HTTP request sent, awaiting response... 401 UNAUTHORIZED
    Connecting to 127.0.0.1:5000... connected.
    HTTP request sent, awaiting response... 500 INTERNAL SERVER ERROR
    2016-02-15 11:52:41 ERROR 500: INTERNAL SERVER ERROR.
    binux
        28
    binux  
       2016-02-15 23:27:18 +08:00 via Android
    @l0wkey 日志,栈信息
    l0wkey
        29
    l0wkey  
       2016-02-15 23:58:55 +08:00
    @binux
    日志无相关信息..
    binux
        30
    binux  
       2016-02-16 02:12:07 +08:00
    @l0wkey webui 出错时的日志
    l0wkey
        31
    l0wkey  
       2016-02-16 11:16:37 +08:00
    @binux
    [E 160215 11:35:00 app:1423] Exception on /results/dump/zhihu.json [GET]
    Traceback (most recent call last):
    File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app
    respOnse= self.full_dispatch_request()
    File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
    File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
    File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
    File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
    File "/usr/local/lib/python2.7/dist-packages/pyspider/webui/result.py", line 37, in dump_result
    resultdb.get(project, 'any')
    File "/usr/local/lib/python2.7/dist-packages/pyspider/database/mysql/resultdb.py", line 99, in get
    where=where, where_values=(taskid, )):
    File "/usr/local/lib/python2.7/dist-packages/pyspider/database/basedb.py", line 69, in _select2dic
    dbcur = self._execute(sql_query, where_values)
    File "/usr/local/lib/python2.7/dist-packages/pyspider/database/basedb.py", line 36, in _execute
    dbcur.execute(sql_query, values)
    File "/usr/lib/python2.7/dist-packages/mysql/connector/cursor.py", line 515, in execute
    self._handle_result(self._connection.cmd_query(stmt))
    File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app
    respOnse= self.full_dispatch_request()
    File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
    File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
    File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
    File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
    File "/usr/local/lib/python2.7/dist-packages/pyspider/webui/result.py", line 37, in dump_result
    resultdb.get(project, 'any')
    File "/usr/local/lib/python2.7/dist-packages/pyspider/database/mysql/resultdb.py", line 99, in get
    where=where, where_values=(taskid, )):
    File "/usr/local/lib/python2.7/dist-packages/pyspider/database/basedb.py", line 69, in _select2dic
    dbcur = self._execute(sql_query, where_values)
    File "/usr/local/lib/python2.7/dist-packages/pyspider/database/basedb.py", line 36, in _execute
    dbcur.execute(sql_query, values)
    File "/usr/lib/python2.7/dist-packages/mysql/connector/cursor.py", line 515, in execute
    self._handle_result(self._connection.cmd_query(stmt))
    File "/usr/lib/python2.7/dist-packages/mysql/connector/connection.py", line 488, in cmd_query
    result = self._handle_result(self._send_cmd(ServerCmd.QUERY, query))
    File "/usr/lib/python2.7/dist-packages/mysql/connector/connection.py", line 395, in _handle_result
    raise errors.get_exception(packet)
    DatabaseError: 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
    [I 160215 11:35:00 _internal:87] 127.0.0.1 - - [15/Feb/2016 11:35:00] "GET /results/dump/zhihu.json HTTP/1.1" 500 -
    binux
        32
    binux  
       2016-02-16 11:36:58 +08:00
    @l0wkey 你访问 http://localhost:5000/task/project:any 也 500 吗?
    l0wkey
        33
    l0wkey  
       2016-02-16 11:45:36 +08:00
    @binux
    /task/project:any 404
    /task/project:_NAME 也 404

    指的 /tasks?project=_NAME 么?这个访问正常
    binux
        34
    binux  
       2016-02-16 12:18:36 +08:00
    @l0wkey project 替换成你导出的 project
    l0wkey
        35
    l0wkey  
       2016-02-16 12:30:57 +08:00
    @binux
    /task/_NAME:any 404
    /task/_NAME 400
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2656 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 106ms UTC 15:12 PVG 23:12 LAX 08:12 JFK 11:12
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86