凌晨不睡覺 用爬蟲抓取京東數(shù)據(jù)

在酒店隔離第10天
凌晨的廈門還是有些涼,我把黑色衛(wèi)衣的帽子戴上
仿佛我是名在網(wǎng)絡(luò)上為維護(hù)世界和平而重拳出擊的黑客......
直到看了看我的發(fā)量.. 想想算了還是當(dāng)個(gè)普通人比較好

前陣子學(xué)了爬蟲,一直沒用來(lái)實(shí)戰(zhàn)
突然想試試, 我說(shuō)可以, 很快啊
上來(lái)就是一左重蹬 右鞭腿 左刺拳..

爬蟲有啥用

大數(shù)據(jù)時(shí)代, 爬蟲用來(lái)獲取互聯(lián)網(wǎng)中的有價(jià)值的數(shù)據(jù)
比如爬取微博 積木的小姐姐啦
分析pronhub有沒有你女朋友的視頻啦

爬到的數(shù)據(jù)庫(kù)截圖

image.png

建表語(yǔ)句


/*
 Source Server Type    : MySQL
 Source Server Version : 50730
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `jd_item`;
CREATE TABLE `jd_item` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `create_time` timestamp NULL DEFAULT NULL COMMENT '創(chuàng)建時(shí)間',
  `type` bigint(1) DEFAULT NULL COMMENT '類型',
  `sku` bigint(20) DEFAULT NULL COMMENT '最小商品單元',
  `spu` bigint(20) DEFAULT NULL COMMENT '聚合單元',
  `item_name` text COLLATE utf8mb4_unicode_ci COMMENT '商品名',
  `img` text COLLATE utf8mb4_unicode_ci COMMENT '圖片url',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=348 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用戶';

SET FOREIGN_KEY_CHECKS = 1;


建立項(xiàng)目, 上代碼

創(chuàng)建maven工程,引入spring boot
pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>JingDongGetDemo</name>
    <description>JingDongGetDemo</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.11.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.6</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>



封裝http請(qǐng)求類

package com.example.demo.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.apache.tomcat.jni.OS;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.UUID;

/**
 * 封裝http請(qǐng)求類
 */
@Component
@Slf4j
public class HttpUtils {
    String cookie = "__jdu=15964473360901187258403; shshshfpa=fadd29f9-813e-e8c5-fad1-5e70d45f5276-1596617912; shshshfpb=lgnFkT9%20fxrnZdfzawNuExA%3D%3D; o2State={%22webp%22:true}; pinId=sAzz8XNBRxQF0-GrxufAZLV9-x-f3wj7; pin=jd_49802f10b0cfc; unick=jd_49802f10b0cfc; _tp=yfPXFZws%2F1K7xphvbgdzaamZ1L9rpl0RAQIHmzRCPQM%3D; _pst=jd_49802f10b0cfc; user-key=a109a42d-1a2b-49d3-bd98-53783efeaa94; areaId=18; ipLoc-djd=18-1482-1485-49034; cn=20; unpl=V2_ZzNtbUtVQUFwDhZQeBpfVmIFGwhLAkIdcAhAU3lLXAViV0UKclRCFnQURldnGV8UZAIZXUFcQhxFCENkexhdBWMGEV5EVnMlMEsWBi8FXAdkAxJURlVAEXEIRVV%2bEFsAZjMRXXJWcxVxAEFRfh9eB2ACGlxCV0oTdgxPUXobbDVnCxZtQlZEFnQOQlN%2fGl41sa2GiMromqXQ3uz6rpTs0O6oxuPEZ0McdQpOVXoZWwZXAiJcchYtFXYARlR4VFwBbwQXWERVQRJ0AEdUexBaBmMKF1xAZ0Ildg%3d%3d; __jdv=122270672|www.zhihu.com|t_1001542270_1003231966_4000320817_3002725071|tuiguang|833e47a5222b478d8d0941763c114eff|1607775130483; PCSYCityID=CN_350000_350200_350203; TrackID=1vODXrK7bZO2EpDh1Nm6sfAqCk-Gs3dPa04wZrr88-S-XPgS5RmPdRgOkuyjgDCzx2l0bqptjiyuNbfelGhkPs7DZ-HlXTRWLdRgbeyueJDoB9TE9EWxFy0YQZ5CZBDGe; thor=762FF186473632AA10BE04F04DD8167499B0ED4286B401207CEE4E033A5989B5862D74A22CEE3390783A6D473BFD74E494C4013BBEA8D5C4D930A373DE163CDDDB5E5902ED9FF16E0B0AEAD53CB7EC3DE05C85A08AE5187A72BB58F825939F3DFB0A273D903500254B0E25CEC29CF7967E7C477315C18A139D9127C91D116828DCF057F4BDB76479B81213D06249FF700DD79CF1ED15C4E4BDCF3E9A6DFB9219; ceshi3.com=000; __jda=76161171.15964473360901187258403.1596447336.1608198065.1608206528.119; __jdb=76161171.6.15964473360901187258403|119.1608206528; __jdc=76161171; shshshfp=96550553530deab8d4b189c0755c3ff2; shshshsID=a55dfa051705e3f0f93c49319b54e32d_3_1608207381885";

    /**
     * 連接池管理器
     */
    private PoolingHttpClientConnectionManager cm;

    /**
     * 構(gòu)造器
     */
    public HttpUtils() {
        this.cm = new PoolingHttpClientConnectionManager();

        // 設(shè)置最大連接數(shù)
        this.cm.setMaxTotal(100);
        // 每個(gè)主機(jī)數(shù)連接數(shù)
        this.cm.setDefaultMaxPerRoute(10);
    }

    /**
     * 根據(jù)url下載數(shù)據(jù)
     *
     * @param url
     * @return
     */
    public String doGet(String url) {

        // 獲取http client對(duì)象
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(this.cm).build();

        // 創(chuàng)建http請(qǐng)求對(duì)象 設(shè)置url地址
        HttpGet httpGet = new HttpGet(url);
//        httpGet.setHeader("Cookie",  cookie);
        httpGet.setHeader("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36");
        httpGet.setConfig(this.getConfig());

        CloseableHttpResponse response = null;
        try {

            // 使用http client
            response = httpClient.execute(httpGet);

            // 發(fā)起請(qǐng)求獲取響應(yīng)
            if (response.getStatusLine().getStatusCode() == 200) {

                // 判斷響應(yīng)體是否不為空
                if (response.getEntity() != null) {
                    String string = EntityUtils.toString(response.getEntity(), "utf-8");
                    return string;
                } else {
                    return "";
                }

            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return "";
    }

    /**
     * 設(shè)置請(qǐng)求配置
     *
     * @return
     */
    private RequestConfig getConfig() {

        RequestConfig requestConfig = RequestConfig.custom()
                // 創(chuàng)建連接時(shí)間
                .setConnectTimeout(1000)
                // 獲取連接的最長(zhǎng)時(shí)間
                .setConnectionRequestTimeout(1000)

                // 獲取數(shù)據(jù)時(shí)間
                .setSocketTimeout(10000)
                .build();
        return requestConfig;
    }

    /**
     * 下載圖片
     *
     * @param url
     * @return 圖片硬盤地址
     */
    public String doGetImg(String url) {

        // 獲取http client對(duì)象
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(this.cm).build();

        // 創(chuàng)建http請(qǐng)求對(duì)象 設(shè)置url地址
        HttpGet httpGet = new HttpGet(url);

        httpGet.setConfig(this.getConfig());

        CloseableHttpResponse response = null;
        try {

            // 使用http client
            response = httpClient.execute(httpGet);

            // 發(fā)起請(qǐng)求獲取響應(yīng)
            if (response.getStatusLine().getStatusCode() == 200) {

                // 判斷響應(yīng)體是否不為空
                if (response.getEntity() != null) {

                    // 獲取圖片的后綴
                    String extImg = url.substring(url.lastIndexOf("."));

                    // 重命名圖片
                    String picName = UUID.randomUUID().toString() + extImg;

                    // 下載圖片
                    File file = new File("/Users/giaogiao/Documents/hewei/code/myCode/JingDongGetDemo/src/main/resources/static/img/" + picName);
                    OutputStream outputStream = new FileOutputStream(file);
                    response.getEntity().writeTo(outputStream);

                    // 返回圖片名稱
                    return picName;

                } else {
                    return "";
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return "";
    }

}

爬蟲定時(shí)任務(wù), 核心代碼


package com.example.demo.task;

import com.example.demo.pojo.JdItem;
import com.example.demo.service.JdItemService;
import com.example.demo.utils.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.sql.Date;

/**
 * 定時(shí)任務(wù)
 */
@Component
@Slf4j
public class ItemTask {

    @Autowired
    private HttpUtils httpUtils;

    @Autowired
    private JdItemService jdItemService;

    // 第一次完成后的間隔時(shí)間,100秒
    @Scheduled(fixedDelay = 100 * 1000)
    public void task() {


//        http://pua.show/index.php?act=pl&id=200
        log.debug("task....");

        // 分頁(yè)查詢
        String url = "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&wq=%E6%89%8B%E6%9C%BA&page=1&s=1&click=0";
//        String url = "https://movie.douban.com/top250";


        String htmlString = httpUtils.doGet(url);
        log.debug("htmlString:" + htmlString);


        log.debug("完成");

    }

    /**
     * 解析數(shù)據(jù)
     */
    private void parse(String htmlString) {
        Elements goodsLists = Jsoup.parse(htmlString).select("#J_goodsList > ul > li");

        for (Element element : goodsLists) {

            // 獲取所有SKU
            Elements items = element.select("li.ps-item");

            for (Element item : items) {

                Long sku = Long.valueOf(item.select("[data-sku]").attr("data-sku"));
                Long spu = null;

                String color = item.select("[title]").attr("title");
                String title = color + element.select("em").text();
                String img = item.select("[data-lazy-img]").attr("data-lazy-img");


                // 獲取spu
                if (element.attr("data-spu").equals("")) {
                    spu = sku;
                } else {
                    spu = Long.valueOf(element.attr("data-spu"));
                }

                JdItem jdItem = new JdItem();
                jdItem.setCreateTime(new Date(new java.util.Date().getTime()));
                jdItem.setType(0L);
                jdItem.setSku(sku);
                jdItem.setSpu(spu);
                jdItem.setItemName(title);
                jdItem.setImg(httpUtils.doGetImg("https:" + img));

                jdItemService.save(jdItem);

            }
        }
    }
}

本項(xiàng)目爬取京東只是一個(gè)引子,一個(gè)最基礎(chǔ)的案例, 將來(lái)還會(huì)想到其他比較好玩的項(xiàng)目,我再來(lái)分享

本項(xiàng)目?jī)?yōu)化和改進(jìn)的點(diǎn):

  • 比較簡(jiǎn)易,沒有使用爬蟲框架 如webmagic
  • 沒有多線程優(yōu)化
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鞭执,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刊咳,更是在濱河造成了極大的恐慌断医,老刑警劉巖囤踩,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件近弟,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡枯夜,警方通過(guò)查閱死者的電腦和手機(jī)弯汰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)湖雹,“玉大人咏闪,你說(shuō)我怎么就攤上這事∷だ簦” “怎么了鸽嫂?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)征讲。 經(jīng)常有香客問(wèn)我据某,道長(zhǎng),這世上最難降的妖魔是什么诗箍? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任癣籽,我火速辦了婚禮,結(jié)果婚禮上扳还,老公的妹妹穿的比我還像新娘才避。我一直安慰自己橱夭,他們只是感情好氨距,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著棘劣,像睡著了一般俏让。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茬暇,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天首昔,我揣著相機(jī)與錄音,去河邊找鬼糙俗。 笑死勒奇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的巧骚。 我是一名探鬼主播赊颠,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼格二,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了竣蹦?” 一聲冷哼從身側(cè)響起顶猜,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎痘括,沒想到半個(gè)月后长窄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纲菌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年挠日,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翰舌。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肆资,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出灶芝,到底是詐尸還是另有隱情郑原,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布夜涕,位于F島的核電站犯犁,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏女器。R本人自食惡果不足惜酸役,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驾胆。 院中可真熱鬧涣澡,春花似錦、人聲如沸丧诺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)驳阎。三九已至抗愁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間呵晚,已是汗流浹背蜘腌。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饵隙,地道東北人撮珠。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像金矛,于是被迫代替她去往敵國(guó)和親芯急。 傳聞我的和親對(duì)象是個(gè)殘疾皇子倘潜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容