Python爬取京东商品信息分析罩杯分布

看到这篇 文章 受的启发,干脆自己也来爬试试

一、准备工作

打开京东,搜索 文胸,就从这开始爬吧



后面的商品大概就没什么购买量了,所以爬个15页就差不多了。
分析下 url, 可以发现 page 控制页数,并且每次增加两页,所以可以很简单的写出我们要爬取15页的商品 url 列表。


由于每个购买者所购买的商品尺寸和型号存在评论里,所以我们得进去爬取每个商品的所有评论部分。
首先得获得每个商品的详细链接。

发现这些链接有的隐藏在 JS 内,所以用 selenium + BeautifulSoup 爬取

pages = set()
links = []
def get_Links(url):
    global pages
    global links
    driver = webdriver.PhantomJS()
    driver.get(url)
    web_data = driver.page_source
    soup = BeautifulSoup(web_data, 'lxml')
    all_imgs = soup.find_all(class_="p-img")
    for link in all_imgs:
        lin = link.find_all('a')[0].get("href")
        if lin not in pages:
            links.append(lin)
            pages.add(lin)

由于担心有的商品链接会重复,建了个集合,但实际上发现并没有重复的链接,集合和列表长度都一样。
得到了每个商品的链接后,(15页是900多个),接着需要分别爬取每个商品的评论中的尺寸信息。


在网页源代码中并没有发现我们想要信息,显然是存在 JS 内。
xhr 内并没有发现,反而是在 JS 内,找了挺久的发现了,如下图。
我们想要的信息存在 product 这里


复制下 Request URL,打开看看,果然我们想要的信息就在里面,尺寸,评论等。正则获取下就行



分析下 URL ,发现 page 是控制页数,product 是商品的 ID 号, 看了下每页都只有10个评论,所以 pagesize就是每页的页数。
那么我们只要用最大的评论数,除以10,就是 page 最大的页数了
既然 product 是 商品 ID 号,在第一步找出所有商品的链接时,商品的 ID 号就在 URL 里面,提取一下就能获得,再传入这里的 URL,就可以获得每个商品对应的评论。
那么评论数怎么获得,有很多方法。
首页就有评论数量,但也是存在 JS 里,用 selenium 显然浪费资源了,特别爬取这么多数据的时候
刷新下网页,发现在 JS 里有个 product summaries,这不是摘要的意思么


点进去看看,果然有评论数量,用正则提取下就行



分析下 URL, 最后面的是时间戳,删掉了并没什么关系,referrenced 后面跟的还是商品 ID,那么同上一样传入商品 ID 就可以获得评论数量了

二、完整代码

先获取所有商品的链接,再爬取每个商品的评论,写入文件就行,由于 excel 比较慢,就用 csv 吧。
出问题的地方可能很多,就用个大的异常统一处理吧

import requests
from bs4 import BeautifulSoup
import urllib
import csv
import codecs
from selenium import webdriver
from multiprocessing.dummy import Pool
import re
import os

headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
    }


def get_Links(url):
    global pages
    global links
    driver = webdriver.PhantomJS()
    driver.get(url)
    web_data = driver.page_source
    soup = BeautifulSoup(web_data, 'lxml')
    all_imgs = soup.find_all(class_="p-img")
    for link in all_imgs:
        lin = link.find_all('a')[0].get("href")
        if lin not in pages:
            links.append(lin)
            pages.add(lin)

def get_Title(url):
    if re.match('http:', url) == None:
        url = 'http:' + url
    
    r = requests.get(url, headers=headers)
    soup = BeautifulSoup(r.text, 'lxml')
    title = soup.find(class_="sku-name").text.strip()
    return title
    

def get_CommentCount(good_ID):
    ur = 'http://club.jd.com/comment/productCommentSummaries.action?referenceIds='
    url = ur + good_ID
    r = requests.get(url)
    count = re.findall(r'"CommentCount":(\d*),"',r.text)
    return int(int(count[0])/10)
    

def wirte_Title():
    csvfile = codecs.open('xz.csv', 'w+', encoding='utf-8')
    title = '\ufeff商品名'
    writer = csv.writer(csvfile)
    data = (title, '尺寸', '评论', '时间')
    writer.writerow(data)
    csvfile.close()
    
        
def get_Comment(good_ID, nums, name):
    ur = 'http://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv11&productId={productId}&score=0&sortType=6&page={page}&pageSize=10&isShadowSku=0'
    nums = int(nums)
    urls = (ur.format(productId=good_ID, page=i)for i in range(0, nums+1))
    #p = Pool(4)
    for url in urls:
        try:
            r = requests.get(url)
            r.encoding = r.apparent_encoding
            web_data = r.text

            size_onepage = re.findall(r'"productSize":"(.*?)"', web_data)
            comment_onepage = re.findall(r'"content":"([^<]*?)"',web_data)
            time_onepage = re.findall(r'[^>]","creationTime":"([^<]*?)"',web_data)
        
            if len(size_onepage) == len(comment_onepage) ==len(time_onepage):
                csvfile = codecs.open('xz.csv', 'r+', encoding='utf-8')
                csvfile.seek(0, os.SEEK_END)
                writer = csv.writer(csvfile)

                for size, comment, time in zip(size_onepage, comment_onepage, time_onepage):
                    data = (name, size, comment, time)
                    writer.writerow(data)
                    #print('Done ten')

            csvfile.close()
        except:
            print('get infomation error')

if __name__ == '__main__':
    
    urls = ("https://search.jd.com/Search?keyword=%E6%96%87%E8%83%B8&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&offset=4&page={}&s=1&click=0".format(i) for i in range(1,32,2))
    pages = set()
    links = []
    #for url in urls:
        #get_links(url)
    
    pool = Pool(4)
    pool.map(get_Links, urls)
    pool.close()
    pool.join()
    wirte_Title()
    for link in links:
        try:
            title = get_Title(link) 
            product_ID = re.findall(r'item.jd.com/(\d*).html', link)[0]
            count = get_CommentCount(product_ID)
            get_Comment(product_ID, count, title)
            print('Done one good')
        except:
            print('get link error')

看看效果


爬了大概半小时,大概 5w+ 了

三、简单分析

好像ABCD之类也有细分的,嫌太麻烦了,就改了下代码,size 直接爬 ABCDEF了

import requests
from bs4 import BeautifulSoup
import urllib
import csv
import codecs
from selenium import webdriver
from multiprocessing.dummy import Pool
import re
import os

headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
    }


def get_Links(url):
    global pages
    global links
    driver = webdriver.PhantomJS()
    driver.get(url)
    web_data = driver.page_source
    soup = BeautifulSoup(web_data, 'lxml')
    all_imgs = soup.find_all(class_="p-img")
    for link in all_imgs:
        lin = link.find_all('a')[0].get("href")
        if lin not in pages:
            links.append(lin)
            pages.add(lin)

def get_Title(url):
    if re.match('http:', url) == None:
        url = 'http:' + url
    
    r = requests.get(url, headers=headers)
    soup = BeautifulSoup(r.text, 'lxml')
    title = soup.find(class_="sku-name").text.strip()
    return title
    

def get_CommentCount(good_ID):
    ur = 'http://club.jd.com/comment/productCommentSummaries.action?referenceIds='
    url = ur + good_ID
    r = requests.get(url)
    count = re.findall(r'"CommentCount":(\d*),"',r.text)
    return int(int(count[0])/10)
    

def wirte_Title():
    csvfile = codecs.open('xz_type.csv', 'w+', encoding='utf-8')
    title = '\ufeff商品名'
    writer = csv.writer(csvfile)
    data = (title, '尺寸', '评论', '时间')
    writer.writerow(data)
    csvfile.close()
    
        
def get_Comment(good_ID, nums, name):
    ur = 'http://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv11&productId={productId}&score=0&sortType=6&page={page}&pageSize=10&isShadowSku=0'
    nums = int(nums)
    urls = (ur.format(productId=good_ID, page=i)for i in range(0, nums+1))
    #p = Pool(4)
    for url in urls:
        try:
            r = requests.get(url)
            r.encoding = r.apparent_encoding
            web_data = r.text

            size_onepage = re.findall(r'"productSize":"(.*?)"', web_data)
            comment_onepage = re.findall(r'"content":"([^<]*?)"',web_data)
            time_onepage = re.findall(r'[^>]","creationTime":"([^<]*?)"',web_data)
        
            if len(size_onepage) == len(comment_onepage) ==len(time_onepage):
                csvfile = codecs.open('xz_type.csv', 'r+', encoding='utf-8')
                csvfile.seek(0, os.SEEK_END)
                writer = csv.writer(csvfile)

                for size, comment, time in zip(size_onepage, comment_onepage, time_onepage):
                    try:
                        sizetype = re.search('[A-Z]', size)
                        if sizetype:
                            s_type = sizetype.group()
                            data = (name, s_type, comment, time)
                            writer.writerow(data)
                            #print('Done ten')
                    except:
                        print('get_sizetype_error')

                csvfile.close()
        except:
            print('get infomation error')
            #print(url)

if __name__ == '__main__':
    
    urls = ("https://search.jd.com/Search?keyword=%E6%96%87%E8%83%B8&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&offset=4&page={}&s=1&click=0".format(i) for i in range(1,32,2))
    pages = set()
    links = []
    #for url in urls:
        #get_links(url)
    
    pool = Pool(4)
    pool.map(get_Links, urls)
    pool.close()
    pool.join()
    wirte_Title()
    for link in links:
        try:
            title = get_Title(link) 
            product_ID = re.findall(r'item.jd.com/(\d*).html', link)[0]
            count = get_CommentCount(product_ID)
            get_Comment(product_ID, count, title)
            print('Done one good')
        except:
            print('get link error')
            #print(link)

爬了大概 30W+,把开始的 url 链接改多点能爬更多,但担心被京东封 IP ,就先爬这么多吧。
清洗下数据,直接用 excel 打开,在 size 列排序,有一些 M 的背心之类,居然还有 男士内裤也爬进去了一个,都删掉。
统计下 ABCDEFG的数量,做个饼图


A和B占了 80% 以上,D及以上不到 5%。
C占了12%。
感觉有意思做了下,数据并不是太严谨,娱乐一下哈

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

推荐阅读更多精彩内容