JAVA爬取淘宝、京东、天猫以及苏宁商品历史价格(二)

写在最前

    写的仓促,有很多地方可能没有解释或者描述到位,大家有什么疑问欢迎评论或者私聊。爬取商品历史价格用的网站为http://www.tool168.cn/history/。想看代码可以直接看最后,除了html请求接口(也好写),其他直接可以用。

爬取问题汇总

1.部分商品未被收录(新出产品或者下单为0的商品),但是绝大多数商品都是收录的,完全可以满足我们的需求了。
2.反爬策略已经算是中上级了,需要花点心思研究。例如:请求头、token校验以及IP请求峰值限制,每天IP最大访问量。
3.页面会有部分改变(算是反爬策略的一种)。

爬取问题解决

爬取过程如下

在这里插入图片描述

请求地址拼接

    http://www.tool168.cn/history/请求地址格式如下,这里需要注意的地方是,请求这个地址,并不能获取商品的具体信息,只是获取到checkCode的。

http://www.tool168.cn/?m=history&a=view&k=url

大家只需要根据不同的电商的商品格式替换到url即可。
京东:https://item.jd.com/100009082466.html
淘宝:https://detail.tmall.com/item.htm?id=599621867171
苏宁:https://product.suning.com/0000000000/11343357124.html

    通过get请求,解析html页面,然后获取到checkCodeId。第一步工作就完成了。
在这里插入图片描述

数据请求头校验

    第二步,发送post请求,请求http://www.tool168.cn/dm/ptinfo.php这个post请求,这个请求会根据上一步获取的checkCode进行校验,然后返回相应的数据(还有一个con参数不要忘记,值就是第一步的商品链接)。
在这里插入图片描述

数据爬取

    这个时候打开返回体,会看到code这个字段,这个才是至关重要的校验码,然后根据这个code校验码发送http://www.tool168.cn/dm/history.php?code=「code」&t= post请求,这里面code参数就是code校验码,t可以不传。
就这里!就这里!!就这里!!!在这里加代理,网站是在这里进行瞬时请求峰值限制的,所以为了提高爬取上线,加个吧。
在这里插入图片描述

数据解析

    终于过五关斩六将到了最后一步了,在上一步的请求中,查看response,这里面就是你想要的数据了。(截图中为preveiw,方便大家看的)。到此,就获得了该商品的数据。
在这里插入图片描述

代码

 /**
     * @Description: parsePrice   获得某个商品的价格信息
     * @param itemDetailsVO
     * @param pid
     * @return 
     * @throws IOException 
     * @throws ParseException 
     */
    @SuppressWarnings("unchecked")
    private static void parsePrice(ItemDetailsVO itemDetailsVO, String itemUrl) throws ParseException, IOException{
        CloseableHttpClient httpclient = HttpClients.createDefault();
        //注意  非当前页面
        String html = HttpClientUtils.getHtml("http://www.tool168.cn/?m=history&a=view&k="+itemUrl,new HashMap<String, Object>());
        String checkCode = Jsoup.parse(html).select("#checkCodeId").attr("value");
        HttpPost httpPost = new HttpPost("http://www.tool168.cn/dm/ptinfo.php");
        //设置代理
//        RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig)
//                .setProxy(new HttpHost("myotherproxy", 8080))
//                .build();
//        httpPost.setConfig(config);
        List <NameValuePair> nvps = new ArrayList <NameValuePair>();
        nvps.add(new BasicNameValuePair("checkCode", checkCode));
        nvps.add(new BasicNameValuePair("con", itemUrl));
        try
        {
            httpPost.setEntity(new UrlEncodedFormEntity(nvps));
        } catch (UnsupportedEncodingException e)
        {
            throw ExceptionFactory.encodingException();
        }
        CloseableHttpResponse codeResponse = httpclient.execute(httpPost);
        try {
            HttpEntity codeEntity = codeResponse.getEntity();
            String str = EntityUtils.toString(codeEntity,"UTF-8");
            Gson gson = new Gson();
            Map<String, Object> hashMap = gson.fromJson(str, Map.class);
            List <NameValuePair> priceNvps = new ArrayList <NameValuePair>();
            priceNvps.add(new BasicNameValuePair("code", hashMap.get("code").toString()));
            priceNvps.add(new BasicNameValuePair("t", ""));
            //历史价格请求  post
            HttpPost priceHttpPost = new HttpPost("http://www.tool168.cn/dm/history.php?code=" + hashMap.get("code").toString() + "&t=");
            priceHttpPost.setEntity(new UrlEncodedFormEntity(priceNvps));
            CloseableHttpResponse priceResponse = httpclient.execute(priceHttpPost);
            try
            {
                HttpEntity priceEntity = priceResponse.getEntity();
                String str2 = EntityUtils.toString(priceEntity,"UTF-8");
                if (str2.contains("chart(\""))
                {
                    //处理返回的response
                    str2 = str2.substring(str2.indexOf("chart(\"") + 7, str2.lastIndexOf("]") + 1);
                    String[] reStrings = str2.split("]");
                    for (int i = 0; i < reStrings.length; i++)
                    {
                        reStrings[i] = reStrings[i].substring(reStrings[i].indexOf("(")+1, reStrings[i].indexOf("\"")-1).replaceAll("\\),", "-");
                    }
                    setMaxMin(itemDetailsVO, reStrings);
                }else if (str2.contains("chart(\'"))
                {
                    //处理返回的response
                    str2 = str2.substring(str2.indexOf("chart(\'") + 7, str2.lastIndexOf("]") + 1);
                    String[] reStrings = str2.split("]");
                    for (int i = 0; i < reStrings.length; i++)
                    {
                        reStrings[i] = reStrings[i].substring(reStrings[i].indexOf("(")+1, reStrings[i].indexOf("\"")-1).replaceAll("\\),", "-");
                    }
                    setMaxMin(itemDetailsVO, reStrings);
                }else {
                    //无数据或者解析异常或者其他异常报错
                    itemDetailsVO.setTrend(new LinkedList<Map<String,Object>>());
                    itemDetailsVO.setPrice("-1");
                    itemDetailsVO.setMaxPrice("-1");
                    itemDetailsVO.setMinPrice("-1");
                }
                EntityUtils.consume(priceEntity);
            } finally
            {
                priceResponse.close();
            }
            EntityUtils.consume(codeEntity);
        } finally {
            codeResponse.close();
       }
    }
    /**
     * @Description: setMaxMin 设置最高价格  最低价格以及当前价格
     * @param itemDetailsVO
     * @param reStrings
     */
    private static void setMaxMin(ItemDetailsVO itemDetailsVO, String[] reStrings) {
        List<Map<String, Object>> list = new LinkedList<Map<String,Object>>();
        double maxPrice = 0;
        double minPrice = 100000000000d;
        for (String temp : reStrings)
        {
            Map<String, Object> map = new HashMap<String, Object>();
            String[] tempStrings = temp.split("-");
            double price = Double.parseDouble(tempStrings[1]);
            if (maxPrice < price)
            {
                maxPrice = price;
            }
            if (minPrice > price)
            {
                minPrice = price;
            }
            map.put("date", DateUtil.formatDateYYYYMMDD(tempStrings[0]));
            map.put("price", price);
            list.add(map);
        }
//        Gson gson = new Gson();
//        JsonArray trendArray= new JsonParser().parse(gson.toJson(list)).getAsJsonArray();
        itemDetailsVO.setTrend(list);
        itemDetailsVO.setPrice(list.get(list.size()-1).get("price").toString());
        itemDetailsVO.setMaxPrice(String.valueOf(maxPrice));
        itemDetailsVO.setMinPrice(String.valueOf(minPrice));
    }

总结

    有三个地方是需要大家格外注意的。

  1. 网站加入了超时检测,在网站请求的时候一定要设置超时限制。
  2. 如果瞬时请求过多,tool168会封掉正在请求的IP,拒绝该ip的任何请求,所以加代理池,延时代理请求是个不错的方法。
  3. 其实前面两个都是不重要的,重要的是,点个赞再走呗!!!

赶得仓促,会慢慢完善修改的,最后贴一张自己的运行实例。
在这里插入图片描述

好的,这个问题涉及到的内容比较复杂,需要用到爬虫数据处理的知识。我会尽力回答,请您耐心阅读。 首先,我们需要使用 Python 编程语言来编写爬虫程序,这里推荐使用 requests 和 BeautifulSoup 库。具体的步骤如下: 1. 导入 requests 和 BeautifulSoup 库。 ```python import requests from bs4 import BeautifulSoup ``` 2. 定义要爬取的网址。以淘宝为例: ```python url = 'https://www.taobao.com' ``` 3. 发送请求获取网页内容。 ```python response = requests.get(url) ``` 4. 解析网页内容,获取所需信息。以获取淘宝首页热销商品为例: ```python soup = BeautifulSoup(response.text, 'html.parser') items = soup.find_all('div', {'class': 'item J_MouserOnverReq'}) for item in items: title = item.find('a', {'class': 'title'}).text.strip() price = item.find('strong').text.strip() print(title, price) ``` 5. 同样的方式,我们可以获取京东苏宁易购网页上的商品信息。 ```python # 京东 url = 'https://www.jd.com' response = requests.get(url) soup = BeautifulSoup(response.text, 'html.parser') items = soup.find_all('li', {'class': 'gl-item'}) for item in items: title = item.find('div', {'class': 'p-name'}).text.strip() price = item.find('div', {'class': 'p-price'}).strong.i.text.strip() print(title, price) # 苏宁易购 url = 'https://www.suning.com' response = requests.get(url) soup = BeautifulSoup(response.text, 'html.parser') items = soup.find_all('div', {'class': 'item-wrap'}) for item in items: title = item.find('div', {'class': 'title-selling-point'}).text.strip() price = item.find('div', {'class': 'price'}).em.text.strip() print(title, price) ``` 以上代码只是简单的示例,实际爬取过程中还需要处理反爬虫机制、异常处理等问题,需要根据实际情况进行调整和优化。 接下来是比较价格的部分。我们可以将爬取到的信息存储到列表中,然后进行比较。以淘宝京东苏宁易购三个网站的商品价格为例: ```python import requests from bs4 import BeautifulSoup # 爬取淘宝商品信息 url = 'https://www.taobao.com' response = requests.get(url) soup = BeautifulSoup(response.text, 'html.parser') items = soup.find_all('div', {'class': 'item J_MouserOnverReq'}) taobao = [] for item in items: title = item.find('a', {'class': 'title'}).text.strip() price = item.find('strong').text.strip() taobao.append({'title': title, 'price': price}) # 爬取京东商品信息 url = 'https://www.jd.com' response = requests.get(url) soup = BeautifulSoup(response.text, 'html.parser') items = soup.find_all('li', {'class': 'gl-item'}) jingdong = [] for item in items: title = item.find('div', {'class': 'p-name'}).text.strip() price = item.find('div', {'class': 'p-price'}).strong.i.text.strip() jingdong.append({'title': title, 'price': price}) # 爬取苏宁易购商品信息 url = 'https://www.suning.com' response = requests.get(url) soup = BeautifulSoup(response.text, 'html.parser') items = soup.find_all('div', {'class': 'item-wrap'}) suning = [] for item in items: title = item.find('div', {'class': 'title-selling-point'}).text.strip() price = item.find('div', {'class': 'price'}).em.text.strip() suning.append({'title': title, 'price': price}) # 比较商品价格 for i in range(len(taobao)): title = taobao[i]['title'] tb_price = float(taobao[i]['price']) jd_price = float(jingdong[i]['price']) sn_price = float(suning[i]['price']) min_price = min(tb_price, jd_price, sn_price) print(title, min_price) ``` 以上代码实现了爬取淘宝京东苏宁易购三个网站上的商品信息,并比较价格,输出最低价格。需要注意的是,这里只是简单的比较了价格,实际应用中还需要考虑其他因素,如运费、售后服务等。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值