一次运行程序,同时获取一下内容:

1. 获取商店详情;
2. 获取当前商品评论;
3. 获取商品的问题、答案;

效果如下图:

Python逆向调试 python爬虫js逆向_json

下面会进行以下几步进行分析(下方演示过程全部使用chrome浏览器);

1.抓包找到对应接口

商店详情https://item-soa.jd.com/getWareBusiness?skuId= 商品评价https://club.jd.com/comment/skuProductPageComments.action 商品相关问题https://question.jd.com/question/getQuestionAnswerList.action 问题的回答https://question.jd.com/question/getAnswerListById.action

2.编写全局控制参数到配置文件

Python逆向调试 python爬虫js逆向_开发语言_02

3.爬虫编写

3.1 店铺详情

def get_shop_info(p_id, max_page):

    q_url = shop_info_base_url + p_id
    res = requests.get(q_url, headers=headers, cookies=cookies).json()
    if res.get("shopInfo") == None:
        return

    shop = res.get("shopInfo").get("shop")
    if shop is None:
        # 没有店铺评分的店,测试下来发现是封掉的店
        return

    shop['wname'] = res.get('wareInfo').get("wname")
    saveDataTool.save_shop_info(p_id, shop)
    get_comments(p_id, max_page)
    get_questions(p_id, max_page)

3.2 商品评论

def get_comments(p_id, max_page):

    print('准备--获取店铺ID为<%s>的评价数据...' % (p_id))
    index = 0
    while True:
        try:
            print('准备--开始获取第%d页...' % (index + 1))
            params.update({'productId': p_id})
            res = requests.get(comment_base_url,
                               headers=headers,
                               cookies=cookies,
                               params=params).json()

            maxPage = res.get('maxPage')

            if len(res.get("comments", [])) > 0:
                saveDataTool.save_comment(p_id, res)
            else:
                print("结束--没有评论内容了,猜测已经是最后一页了...")
                break

            # 只要达到了最大页码条数,无论后面还有没有下一页,当前店铺的评论到此为止
            if max_page > 0 and max_page <= index + 1:
                print("正常终止--<%s>的第%d页触发了限定最大页码数..." % (p_id, index + 1))
                break
            if index >= maxPage - 1:
                print("结束--<%s>的第%d页已是最后一页..." % (p_id, index + 1))
                break
            else:
                index += 1
                params.update({
                    'page': index,
                })
                sleep = random.randint(config['random_start'],
                                       config['random_end'])
                print('开始休眠:%d秒...' % (sleep))
                time.sleep(sleep)  # 下次请求之前随机暂停几秒,防止被封号

        except Exception as err:
            logsTool.log_to_save(id, index, err)
            break

3.3 商品问题

def get_questions(p_id, max_page):
    print('准备--获取店铺ID为<%s>的问题列表数据...' % (p_id))
    index = 1
    while True:
        try:
            print('准备--开始获取问题列表第%d页...' % (index))
            quesiton_params.update({'productId': p_id})
            res = requests.get(question_base_url,
                               headers=headers,
                               cookies=cookies,
                               params=quesiton_params).json()

            totalPage = math.ceil(res.get("totalItem", 0) / 10)
            questionList = res.get("questionList", [])

            if len(questionList) > 0:
                saveDataTool.save_question(p_id, res)
                for question in questionList:
                    answerCount = question.get("answerCount", 0)
                    tempId = question.get('id')
                    # 直接保存
                    if answerCount > 0 and answerCount <= 2:
                        saveDataTool.save_answer(
                            p_id, tempId, question.get('answerList', []))
                    elif answerCount > 2:
                        get_answer(p_id, tempId, max_page)
                    else:
                        continue

            if index >= totalPage:
                print("结束--问题列表<%s>的第%d页已是最后一页..." % (p_id, index))
                break

            # 只要达到了最大页码条数,无论后面还有没有下一页,当前店铺的评论到此为止
            if max_page > 0 and max_page <= index:
                print("正常终止--问题列表<%s>的第%d页触发了限定最大页码数..." % (p_id, index))
                break

            index += 1
            quesiton_params.update({
                'page': index,
            })
            sleep = random.randint(config['random_start'],
                                   config['random_end'])
            print('开始休眠:%d秒...' % (sleep))
            time.sleep(sleep)  # 下次请求之前随机暂停几秒,防止被封号

        except Exception as err:
            logsTool.log_to_save(p_id, index, err)
            break

3.4 问题答案

# 问题;p_id:product_id、 q_id:问题id
def get_answer(p_id, q_id, max_page):

    print('准备--获取问题ID为<%s>的答案列表数据...' % (q_id))
    index = 1
    while True:
        try:
            print('准备--开始获取第%d页answer...' % (index))
            answer_params.update({'questionId': q_id})
            res = requests.get(answer_base_url,
                               headers=headers,
                               cookies=cookies,
                               params=answer_params).json()

            answers = res.get("answers", [])
            if len(answers) > 0:
                saveDataTool.save_answer(p_id, q_id, answers)

            if res.get("moreCount", 0) < 0:
                print("结束--<%s>的answer的第%d页已是最后一页..." % (q_id, index))
                break

            # 只要达到了最大页码条数,无论后面还有没有下一页,当前店铺的评论到此为止
            if max_page > 0 and max_page <= index:
                print("正常终止--<%s>的第%d页触发了限定最大页码数..." % (q_id, index))
                break

            index += 1
            answer_params.update({
                'page': index,
            })
            sleep = random.randint(config['random_start'],
                                   config['random_end'])
            print('开始休眠:%d秒...' % (sleep))
            time.sleep(sleep)  # 下次请求之前随机暂停几秒,防止被封号

        except Exception as err:
            logsTool.log_to_save(q_id, index, err)
            break

4.CSV

Python逆向调试 python爬虫js逆向_爬虫_03

总结:程序一键运行,过程中错误中断自动保存日志到log文件,方便后续分析!但是现在没有添加多线程,大数据量采集数据的话,单线程运行可能需要很久,本案例只是自己纯学习练习使用!源码已同步到知识星 球!