Python简单爬取京东商品列表

直接上代码

#!/usr/bin/python3
# -*- coding: UTF-8 -*-

import urllib.request
import urllib.error
import re
import csv
import time

global_row = 0

'''
需求:
爬取京东商品数据,以‘java’关键字为例。要求使用最基础的urllib和re库。
需要保存书名,价格,评论数,出版社等信息。

实现:
找出页面规律如下
一、每页显示60个商品,但分为两部分。
1. 每页前30个商品,通过search.jd.com/Search?keyword=java接口获取
   每页后30个商品,通过search.jd.com/s_new.php?keyword=java接口获取,这个接口是个XHR请求,通过Chrome的开发者选项可以看出。模拟人向下滚动页面
2. 每个接口有两个关键的参数'page'和's'
   参数'page'好理解,就是页面数。对第一个接口变化规律为1,3,5...,对第二个接口变化规律为2,4,6...;
   参数's'我猜应该是start,也就是起始商品的索引。实际测试时,这个参数变化不是很规律,这里强制设置每页30个,
   这样对第一个接口变化规律1,61,121...,对第二个接口变化规律为31,91,151...
3. 对于获取不到商店名称的情况,再构造chat1.jd.com/api/checkChat请求,获取商店名称。(但还是存在获取不到的情况,页面也不能显示)
'''
def crawl_page(n, csv_writer):
    #上半部分网页
    top_url = 'http://search.jd.com/Search?keyword=java&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&page=%d&s=%d&click=0' % (2*n- 1, 1 + 60*(n - 1))
    content = get_page_content(top_url, True)
    parse_content(content, n, csv_writer)

    #下半部分网页(需要发送XHR请求的)
    current_time = '%.5f' % time.time() 
    url = 'http://search.jd.com/s_new.php?keyword=java&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&page=%d&s=%d&scrolling=y&log_id=%s' %(2*n, 31 + 60*(n - 1), current_time)
    content = get_page_content(url, False)
    parse_content(content, n, csv_writer)

def get_page_content(url, is_top):
    req = urllib.request.Request(url)
    req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3192.0 Safari/537.36')
    if not is_top:
        req.add_header('Referer', 'http://search.jd.com/Search?keyword=java&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&click=0')
        req.add_header('X-Requested-With', 'XMLHttpRequest')
    response = urllib.request.urlopen(req)
    return response.read().decode('utf8')

def get_seller(shop_url):
    req = urllib.request.Request(shop_url)
    req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3192.0 Safari/537.36')
    req.add_header('Referer', 'http://search.jd.com/Search?keyword=java&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&click=0')
    response = urllib.request.urlopen(req)
    content = response.read().decode('utf8')
    print('content', content)
    seller = re.search(r'"seller":"(.*?)"', content)
    if seller:
        #获得的值为类似于"\u58a8\u9a6c\u56fe\u4e66\u65d7\u8230\u5e97",需要转码
        return seller.group(1).encode('latin-1').decode('unicode_escape')
    return ''

def parse_content(content, n, csv_writer):
    li_list = re.findall(r'<li data-sku="\d*" class="gl-item">.*?</li>', content, re.DOTALL)
    for li in li_list:
        #书名
        name_match = re.search(r'<div class="p-name p-name-type-2">.*?<em>(.*?)</em>.*?</div>', li, re.DOTALL)
        name = ''
        if name_match:
            name = re.sub(r'<.*?>', '', name_match.group(1))
        else:
            print('page %d, name is empty' % n)

        #价格
        price_match = re.search(r'<div class="p-price">.*?<i>(.*?)</i>.*?</div>', li, re.DOTALL)
        price = ''
        if price_match:
            price = price_match.group(1)
        else:
            print('page %d, price is empty' % n)
        #评论数
        commit_match = re.search(r'<div class="p-commit">.*?<a .*?>(.*?)</a>.*?</div>', li, re.DOTALL)
        commit = ''
        if commit_match:
            commit = commit_match.group(1)
        else:
            print('page %d, price is empty' % n)

        #出版社(商店)
        shop_match = re.search(r'<div class="p-shop" [^>]*>\s*<span [^>]*><a [^>]*>(.*?)</a>.*?</div>', li, re.DOTALL)
        shop = ''
        if shop_match:
            shop = shop_match.group(1)
        else:
            uid = re.match(r'<li data-sku="(\d*)" class="gl-item">.*?</li>', li, re.DOTALL).group(1)
            seller_url = 'https://chat1.jd.com/api/checkChat?pid=' + uid + '&returnCharset=utf-8'
            shop = get_seller(seller_url)
            if not shop:
                print('page %d, shop is empty' % n)
    
        global global_row
        global_row = global_row + 1
        csv_writer.writerow([str(global_row), name, price, commit, shop])
        

def main():
    with open('output.csv', 'w', encoding='gbk') as f:
        csv_writer = csv.writer(f)
        csv_writer.writerow(['序号', '书名', '价格', '评论数', '出版社'])
        for i in range(1, 6):
            crawl_page(i, csv_writer)
    

if __name__ == '__main__':
    main()

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容