爬虫技术概览

2023-05-16

爬虫介绍

简介

自动化、半自动化从互联网上采集数据的程序。

爬虫框架

一个简单的爬虫框架:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ifdLU0V-1625273924704)(http://m.qpic.cn/psb?/V142fVv21EKO4b/ehGhiSFPmw1GPPzU1LdWwTeX4v5JdcLe9d6KUIg.upE!/b/dL4AAAAAAAAA&bo=SQLDAQAAAAADB6s!&rf=viewer_4)]

如上图,通常爬虫会有一份种子URL,放在待抓取队列,通过scheduler调度这些url,交由downloader去下载网页数据,
进行数据的清洗解析,获取到所需要的信息进行存储,并将新解析出的有用URL放入待抓取队列。

爬虫的各个阶段

调度阶段

下图是调度系统通常需要考虑的一些事情。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ANVlp8b-1625273924706)(http://m.qpic.cn/psb?/V142fVv21EKO4b/Kb8Ov*GsHX5olgwSDQOiTKaXUc8Fk1DvgB4WaFecaQw!/b/dL8AAAAAAAAA&bo=MgKRAAAAAAADB4M!&rf=viewer_4)]

下图是一个简单的调度模块,由一个Crane定时任务+queue队列来实现一个基本的调度。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GkQudYxZ-1625273924707)(http://m.qpic.cn/psb?/V142fVv21EKO4b/N5QsvBPNK6*43qv8XNvhwkUQULxtCrgPBGXw6ISjdSY!/b/dFIBAAAAAAAA&bo=pwGmAQAAAAADByM!&rf=viewer_4)]

下载阶段

通常通过封装HttpClient、HttpUrlConnection来实现下载器。

HttpClient的应用举例

//HttpClient的使用样例,下面是一个GET请求,PostMethod可以发送post请求,同理也可发送delete、put、head请求。 

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.ListUtils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.lang.StringUtils;
import java.io.IOException;
 
public static void main(String[] args) {
    HttpClient httpClient = new HttpClient();
    HttpMethod httpMethod = new GetMethod("http://www.sina.com.cn");
    httpMethod.addRequestHeader("Content-Type", "text/html;charset=utf-8"); //这里设置字符编码,避免乱码
    int statusCode = -1;
    byte[] result = null;
    try {
        statusCode = httpClient.executeMethod(httpMethod);
        if (statusCode != HttpStatus.SC_OK) {//判断返回
            System.out.println("get failure!");
            return;
        }
        if (httpMethod.getResponseBody() != null) {//获取页面数据
            result = httpMethod.getResponseBody();//hm.getStatusLine()――http状态和请求结果
        }
    } catch (HttpException e1) {
        e1.printStackTrace();
    } catch (IOException e2) {
        e2.printStackTrace();
    } finally {
        httpMethod.releaseConnection();
    }

    if (result != null) {
        try {
            String data = new String(result, "UTF-8");//字符编码设置
            System.out.println(data);//测试输出
        } catch (Exception e) {
            LOGGER.info("an exception! e = {}", e);
        }
    }
}
 
//jar包依赖
/*
<dependency>
    <groupId>commons-httpclient</groupId>
    <artifactId>commons-httpclient</artifactId>
    <version>3.1</version>
</dependency>
*/

  1. post请求可以用于模拟登录网页等操作,是常用到的一种请求方式,post请求一般需要携带header、cookie等信息。

  2. 此类方式抓到的数据都是未经过JS渲染的。

  3. todo增加一篇详细的httpclient等下载方式的介绍。以及模拟登录的实现样例。

解析阶段

此阶段主要是将下载阶段获取的html文本或者其他格式的数据进行格式化,抽取出我们要求的信息。
常见的解析手段

正则

todo正则表达式的详细介绍

Xpath

即XML路径语言(XMLPathLanguage),它是一种用来确定XML文档中某部分位置的语言。

比如要定位https://movie.douban.com/ 中右侧的一周口碑榜
只需要一句话:
//*[@id=“billboard”]//tbody/tr/td

如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rDNZssWN-1625273924708)(http://m.qpic.cn/psb?/V142fVv21EKO4b/pWKb8N7KvMub8T5lLC0JYIWRS0nhEvH1Xz5Y6y*G8hQ!/b/dMAAAAAAAAAA&bo=8gRdAQAAAAARB5o!&rf=viewer_4)]

Jsoup

如果要解析一篇文章,由于文章内容分散在各个节点上,此时用正则或者xpath就不太方便了,还是得用Jsoup递归一下所有节点。
todo jsoup的详细介绍
4>其他
其它方式如string.index。
###存储阶段
####es
####db
####hive
####其他
此阶段不过多介绍。

常见的数据抓取方式

web/i版网页抓取

web网页和i版网页是相对比较好抓取的一种页面。通常情况下,数据会存在于html文本、ajax请求中,不过也会遇到一些情况使得抓取变得相当复杂:数据进行了加密、数据存在于图片等载体、请求有验签、未知含义cookie等等。

举例

腾讯视频的播放数、评论数抓取:https://v.qq.com/x/cover/rvkqtjee5rvbj38/f0521wc8x2i.html

  1. 首先根据页面展示关键字去搜索播放、评论数是否存在于html文本中,参见 view-source:https://v.qq.com/x/cover/rvkqtjee5rvbj38/f0521wc8x2i.html,显然播放数存在于html文本中,而评论数不存在。

  2. 打开审查元素(chrome下,左键选择检查),然后进行下面的操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cMekPvcR-1625273924708)(http://m.qpic.cn/psb?/V142fVv21EKO4b/UBMNyLKcqPGMCbDufgtf.enCw5o7yRb.d.PtszNj1sM!/b/dDEBAAAAAAAA&bo=ngWYAgAAAAADByM!&rf=viewer_4)]

3.如上已经拿到了播放数,此时下拉网页,拉的快的话,可以发现评论区没有数据,过了半秒的样子刷新出了数据,此时可以很明显的判断出这是一个ajax请求。

4.此时打开审查元素,切换到Network页面,刷新下网页可以发现有许多的请求,一个html页面会有许多请求。其中有一个 https://coral.qq.com/article/1886906224/commentnum?callback=jQuery112405035975130740553_1504434583371&_=1504434583372 此请求中包含所需要的评论数。
url中的1886906224为评论id,需要在请求主页面的返回结果中获取,1504434583372为时间戳。

模拟浏览器抓取

通过web/i版页面进行抓取有许多的限制,比如有较多的cookie信息需要破解、拼凑,数据加密,拿到的数据非JS渲染后的页面等等。

此时我们可以通过真实的浏览器去做数据抓取,此时强大的selenuim就要出场了!

selenuim包括一些浏览器driver,这些driver可以做一些浏览器所做的事情,通过一些api实现浏览器的控制操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-94J8Wuzh-1625273924709)(http://m.qpic.cn/psb?/V142fVv21EKO4b/l7zSovkF37arOynT4DZSAOuJyqG1oXjpB8xSXpC2M*E!/b/dLgAAAAAAAAA&bo=SQJpAQAAAAADBwE!&rf=viewer_4)]

无头浏览器(伪浏览器),没有GUI,而是具有支持html、js等解析能力的类浏览器程序,支持页面元素的查找、JS的执行等。

由于不进行GUI渲染,所以运行效率上会比真实浏览器要快很多。

在真实的抓取中,考虑到效率问题以及服务器没有界面,我们通常采用无头浏览器,其中htmlunit的js解析引擎是Rhino,对JS的支持不好。所以大多数人采用的是PhantomJS。

常见应用举例
绕过复杂请求模拟打开指定网页,通过api获取网页数据进行解析。
获取cookie通过api模拟登录指定网站,获取登录cookie用于请求对方API接口,抓取该网站的数据。
破解验证码对于拖拽式、点击式验证码,通过phantomJs可以较容易的绕过。

PhantomJs登录微博获取Cookie举例

//文件一:
package com.xxx.service.movie.loki.spider.weibo;

import com.xxx.service.movie.loki.utils.SeleniumUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.image.BufferedImage;
import java.util.Set;

/**
 * Created by xiehonghao on 17/4/25.
 */
public class WeiboLoginCookieSpider {

    private static final Logger LOGGER = LoggerFactory.getLogger(WeiboLoginCookieSpider.class);

    private static final WebDriver driver = SeleniumUtils.getPhantomJSDriver();

    public void getLoginCookie() {
        driver.get("http://weibo.com/tv/v/F07DPgqEG?from=vfun#_loginLayer_1493102099143");
        BufferedImage image = SeleniumUtils.getScreenshot(driver);
        tryLogin();
        Set<Cookie> cookieSet = driver.manage().getCookies();
        int kk = 10;
    }

    private static boolean tryLogin() {
        boolean hasLogined = true;
        //寻找登录窗口元素
        WebElement userNameElement = SeleniumUtils.findElement(driver, By.xpath("//*[@id=\"loginname\"]"));
        if (userNameElement != null) {
            userNameElement.sendKeys("sbmaizang@126.com");
            hasLogined = false;
        }

        if (hasLogined) {
            return true;
        }

        WebElement passwordElement = SeleniumUtils.findElement(driver, By.name("password"));
        if (passwordElement != null) {
            passwordElement.sendKeys("xxxx");
        } else {
            LOGGER.error("tryLogin to baidu failure, not found element TANGRAM_12__password");
            return false;
        }
        WebElement submitElement = SeleniumUtils.findElement(driver, By.xpath("//*[@id=\"pl_login_form\"]/div/div[3]/div[6]/a"));
        if (submitElement != null) {
            submitElement.click();
        } else {
            LOGGER.error("tryLogin failure");
            return false;
        }
        return true;
    }

    public static void main(String[] args) {
        WeiboLoginCookieSpider weiboLoginCookieSpider = new WeiboLoginCookieSpider();
        weiboLoginCookieSpider.getLoginCookie();
    }
}


//文件二:
package com.xxx.service.movie.loki.utils;

import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

/**
 * Created by xiehonghao on 17/3/15.
 */
public class SeleniumUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(SeleniumUtils.class);

    static {
        System.setProperty("phantomjs.binary.path", "你的phantomJs路径");
    }

    public static WebDriver getPhantomJSDriver() {
        WebDriver driver = null;
        try {
            driver = new PhantomJSDriver();
        } catch (Exception e) {
            LOGGER.error("phantomJs driver initialization failure!");
            return null;
        }
        driver.manage().window().maximize();
        return driver;
    }

    public static WebElement findElement(WebDriver driver, By by) {
        try {
            return driver.findElement(by);
        } catch (Exception e) {
            LOGGER.info("find element throws an exception!, e = {}", e);
            return null;
        }
    }

    public static void waitUntilAppear(WebDriver driver, By by, int timeOutInSeconds) {
        WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
        try {
            wait.until(ExpectedConditions.visibilityOfElementLocated(by));
        } catch (TimeoutException e) {
            LOGGER.info("wait element appear throws an exception!, e = {}", e);
        }
    }

    public static BufferedImage getScreenshot(WebDriver driver) {
        BufferedImage bufferedImage = null;
        TakesScreenshot shot = ((TakesScreenshot) driver);
        InputStream inputStream = null;
        try {
            byte[] bytes = shot.getScreenshotAs(OutputType.BYTES);
            inputStream = new ByteArrayInputStream(bytes);
            bufferedImage = ImageIO.read(inputStream);
        } catch (Exception e) {
            LOGGER.error("getScreenshot throws an exception! e = {}", e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (Exception e) {
                    LOGGER.error("close inputStream throws an exception! e = {}", e);
                }
            }
        }
        return bufferedImage;
    }
}

客户端接口抓取

当一些信息存在于客户端,这时候就要涉及客户端抓取了,客户端的数据一般是JSON结构,更加容易解析,不过抓包相对web/i版会比较麻烦,另外对于https抓包还需要在手机上安装抓包工具生成的证书。

常见的抓包工具,这些工具支持i版、web版、客户端等类型的抓包。

抓包工具介绍
charlesmac下的一款小巧强大的抓包工具,支持分析请求数据、设置断点、调试web应用、修改请求的数据,甚至可以修改服务器返回的数据等功能
fiddler和charles支持功能差不多。
wireshark到任何协议的数据(不过除了http、https协议,其它协议的数据也看不懂…)。

抓到数据后,其它流程就和web版、i版抓取类似了。注意抓包时,手机和电脑要在同一个局域网内。

现在拿https抓包做个分析,看下抓包的原理:中间人攻击

首先来看下正常的请求流程。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tFGtyBJc-1625273924710)(http://m.qpic.cn/psb?/V142fVv21EKO4b/kalycb6NaV2tgwSu3NOKA7I5HixJO94i7nRvZuUx8!/b/dLkAAAAAAAAA&bo=WAIxAgAAAAADB0s!&rf=viewer_4)]

下面是中间人攻击抓包的原理图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tN7LHmm7-1625273924710)(http://m.qpic.cn/psb?/V142fVv21EKO4b/p0IUcOj4IxlXOuoxZGEzA24arWy5DE4FcIfzANTnS68!/b/dDcBAAAAAAAA&bo=LgLeAgAAAAADF8I!&rf=viewer_4)]

APP破解抓取

当一些数据仅存在于APP中,且数据请求非http、https或者存在数据加密等难题时,这时候可以尝试下通过破解APP来获取app内已经解析出的数据。

我们来看下我们目前在用的一种破解方法:动态hook修改原代码的执行逻辑,在这之前先来了解一些一下Xposed框架、UIAutomator。

Xposed框架

####介绍:

Xposed框架是一款可以在不修改APK的情况下影响程序、系统运行的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。

原理:

通过替换 /system/bin/app_precesss 程序控制zygote进程,

使得它在系统启动的过程中会加载Xposed框架的jar文件即XposedBridge.jar,

从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持,并且能够允许开发者独立的替代任何class,从后修改framework本身、系统UI又或者随意的一个app。

我们通常用它来实现对一个APP的方法劫持(HOOK),在方法前后嵌入自己的逻辑。

使用方法:

http://blog.csdn.net/p106786860/article/details/52213695

###UIAutomator
一个自动化测试框架,通过该框架可以实现操纵手机,比如进行点击、拖动、输入、打开关闭APP等各种操作。

一个操作流程需要自己去写代码去组合实现,相对按键精灵等工具,这种方式写的程序更加健壮。

todo 教程 UIAutomator模拟淘票票下单

效果演示 http://v.meituan.net/movie/videos/9e2d1f074f2c4568a22792dafc87b963.mp4

破解流程

1.首先APP破解通过需要经过反编译(如果加壳了,需要在反编译前进行脱壳),获取反编译后的代码。

    常见的反编译软件有:
    1) APKtool  
    2) dex2jar  
    3) jd-gui  
    4) 签名工具

2.分析反编译后的代码,找到目标类和方法,此时的代码是高度混淆的,类名、方法名、变量名都是简短的字符如a 、aa、f、ab等。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I0Y4WeQK-1625273924710)(http://m.qpic.cn/psb?/V142fVv21EKO4b/mrVmdPVo8qJntyG6u.S8K7zs5fC.SpccoJ0J51DAbJQ!/b/dL8AAAAAAAAA&bo=*QPjAQAAAAADBz4!&rf=viewer_4)]

此时有一些小技巧用来定位想要的类方法。

1)关键字搜索。 
2)找到输出日志方法,hook该方法分析请求日志)
3) hook相关调用的底层方法,并在其中抛出异常,打出调用栈。

3.定位到想要的方法后,通过Xposed hook框架hook指定代码,在指定方法前后嵌入自己的逻辑。
4.通过UIAutomator等工具实现定时自动触发操作进行数据抓取。

应用举例

抓取淘票票卖品、影票基础价、活动价等数据,在淘票票app上下单后可以展现卖品、价格等数据。通过如下流程进行数据的抓取
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fzP7sulN-1625273924711)(http://m.qpic.cn/psb?/V142fVv21EKO4b/1oPpbYiUgxTS780eolx9SLnbe0CVEH8owkGJW9IDQ.g!/b/dL8AAAAAAAAA&bo=nAR3AgAAAAADB88!&rf=viewer_4)]

  1. 首先UIAutomator模拟点击至下单页面,触发请求卖品数据的方法A的上一层方法B(B方法已经被HOOK)。
  2. 在B方法中请求内部服务器获取待抓取影院队列。此时替换B方法中的影院id等参数,循环调用A方法(即请求淘票票卖品、票价数据的方法)。
  3. 通过对接收请求结果的方法的HOOK,我们可以拿到淘票票异步返回的卖品数据,然后上传至清洗服务器。

以上为个人学习测试所操作,请勿模仿或用于商业用途,本人不负任何法律责任。

#爬虫的对抗
在爬虫的世界,存在着一个死循环:爬虫、反爬虫、反反爬虫、反反反爬虫…

反爬虫策略介绍反反爬虫策略
阈值:如ip请求次数超过限制。常见于
用户请求限制
ip请求次数限制
1.降低请求频率。
2.ip代理池。
Heads:请求必须要携带某些请求header。通常不正常的header会被判定为爬虫。1.对于user agent使用user agent池。
2.根据具体网站设置refer信息。
3.其它header信息视情况而定。
ajax请求ajax请求 一个网页的数据会包含多个ajax请求。1.分析所有请求,定位真正返回数据的请求,构造请求参数。
2.无头浏览器。
验签通常由前端生成信息,后端进行验证。1.调试前端代码,定位验证逻辑代码进行分析出逻辑或定位到代码后直接在工程内通过javascript引擎执行。
2.无头浏览器、app破解。
cookie通常登录、发送请求都需要传递cookie,且有些连续请求页面需要依赖前面请求产生的cookie。1.若需要登录cookie,且难以实现模拟登录,可以手动触发登录获取cookie放入配置中心,定时更换。
2.若需要连续请求,依次模拟请求,并将获取的cookie在后续请求中使用。
3.无头浏览器、app破解。
socket层协议有些APP不通过常用的http、https协议,而是socket连接来传输二进制数据。1.通过app破解,在app内部将数据截获。
数据图片数据以图片的方式进行展示1.OCR识别。
2.机器学习。
验证码通常登录时需要输入验证码,
被封禁时也时常弹出验证码,
分为字符验证码、动作验证码,动作验证码即拖动验证、点击验证。
1.字符验证码:卷积神经网络、OCR识别、打码平台。
2.动作验证码:app自动化测试工具、浏览器自动化测试工具。
数据加密1.分析解密…
2.尝试绕过如app破解、无头浏览器。
行为特征如果用户只请求一个页面,或者有规律的请求,明显不是正常用户。1.尽量随机化操作、随机时间、模拟人类真实操作。
蜜罐设置一些用户触及不到的网页,等着爬虫去爬,爬到了就属于非正常用户。没有好的解决方法。。。。。。
投毒即假数据结合上面的反反爬虫策略,尝试不被对方发现。

ps 本文未经本人同意,不可转载。 by chasexie
以上操作均为测试,未

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

爬虫技术概览 的相关文章

随机推荐

  • c++基础知识第十天:结构体嵌套结构体,结构体作函数参数

    一 结构体嵌套结构体 结构体内的成员可以是另一个结构体 xff08 访问时用 访问到不能访问为止 xff09 1 例如 xff1a 每个老师指导一个学员 xff0c 一个老师的结构体中嵌套一个学生的结构体 include lt iostre
  • ros出现 datatype/md5sum错误

    1 错误图 2 我是在windows用的vs code ssh 另外一台电脑ubuntu18 04系统 xff0c 然后在那边terminal输入rqt plot但是图里面一直空白 xff0c windows这边输出上图报错 一直以为是自己
  • 安卓Android多阶段进度条progress bar附带动画效果

    还在为美工设计出的进度条而发愁吗 xff1f 大家先看效果吧 欢迎加安卓开发交流群 xff1a 308372687 xff08 博主尽可能帮助大家 xff09 转载请注明来源 代码连接 GitHub xff1a https github c
  • 【docker】Docker安装

    版本说明 OS xff1a Centos7 6 x64 Linux内核 3 10 0 1062 12 1 el7 x86 64 Docker Docker version 19 03 14 Docker要求CentOS系统的内核版本高于3
  • Python如何在函数内部使用全局变量

    使用方法 Python在函数内部使用全局变量的一种常用方法如下 xff1a 即首先需在函数外部给一个变量赋初值 xff0c 然后在函数内部用关键字 global 将此变量声明为全局变量 而且 xff0c 不能有形如 global a 61
  • 树莓派3B SWAP空间不足

    在对树莓派3B进行ROS indigo安装时 xff0c 到编译ROS程序这一步时 xff0c 总是失败 xff0c 查看了原因发现 xff0c 在为树莓派安装系统时swap空间没有设置 不过为时未晚 xff0c 现在也可以对swap空间进
  • TX2核心板安装OpenCV3.2(在cuda9.0的环境下)

    今天新到的TX2 xff0c 还有点烫手 xff0c 买来要用在无人机上做视觉的目标识别 xff0c 所以自然要装上OpenCV喽 xff01 TX2核心板买来就自带了cuda9 0 xff0c 据说这个和opencv3不太搭 xff0c
  • c语言面试题 指针30个常错题型

    1 char const p char const p const char p 上述三个有什么区别 xff1f char const p 常量指针 xff0c p的值不可以修改 char const p xff1b 指向常量的指针 xff
  • c++ 笔试面试题 难题精选 持续更新

    第一题 问下面的输出结果是 什么 xff1f include lt stdio h gt include lt iostream gt using namespace std class A protected int m data pub
  • VS2010 添加OnInitDialog的方法

    OnInitDialog 在vs2010中实现为虚函数 所以在 项目 gt 类向导 gt 虚函数 gt 选中要添加的类 xff0c 找到对应虚函数添加即可 就这么简单
  • HBITMAP与BITMAP 的区别 BMP图像的格式

    HBITMAP 是句柄 xff1b BITMAP 是实例 xff1a typedef struct tagBITMAP bm int bmType 必须是BM int bmWidth 指定位图的宽度 xff08 以象素为单位 xff09 i
  • fatal error LNK1281: 无法生成 SAFESEH 映像。

    解决方法 xff1a 1 打开该项目的 属性页 对话框 2 单击 链接器 文件夹 3 单击 命令行 属性页 4 将 SAFESEH NO 键入 附加选项 框中 xff0c 然后点击应用
  • 如何实现科技论文里面的算法

    这是一篇关于如何实现科研论文中算法的简要指南 作者曾实现过很多书本上和科研论文中的复杂算法 xff0c 在这篇文章中作者总结他在研究 xff0c 阅读 xff0c 编码和调试时积累的大量经验 很显然 xff0c 这篇文章主要集中在和计算机科
  • 程序员专用经典语录—看完笑一阵可以,千万不要死循环哦!

    IT人表示屁股上还得纹一个 lt body gt 要不中间来个hello world 真正的程序员喜欢兼卖爆米花 xff0c 他们利用CPU散发出的热量做爆米花 xff0c 可以根据米花 爆裂的速度听出正在运行什么程序 十年生死两茫茫 xf
  • android 自学中的散乱笔记

    1 查看程序运行记录 要在LogCat中查看 其内可选择查看的信息级别 xff0c 比如info xff0c error xff0c debug等等 xff0c 信息可筛选显示 2 xff1a 安装好手机驱动 xff0c 将手机接入usb即
  • java lambda表达式 闭包学习笔记

    我们把这些只拥有一个方法的接口称为函数式接口 声明一个接口是函数式接口 xff1a 编译器会根据接口的结构自行判断 xff08 判断过程并非简单的对接口方法计数 xff1a 一个接口可能冗余的定义了一个Object已经提供的方法 xff0c
  • C++ STL set和multiset的使用 hunst_xiehonghao 总结

    C 43 43 STL set和multiset的使用 std set lt int gt s 那个s这个对象里面存贮的元素是从小到大 排序的 xff0c 因为用std less作为比较工具 1 xff0c set的含义是集合 xff0c
  • 数据结构之车厢调度 思路很重要

    问题描述 假设停在铁路调度站入口处的车厢序列的编号依次为1 xff0c 2 xff0c 3 N 设计一个程序 xff0c 求出所有由此输出的长度为N的车厢序列 要求3节车厢调度的方法 xff0c 1代表进栈 xff0c 0代表出栈 有几点要
  • 判断N 数码是否有解 牛人总结 归并排序

    作者 力的博客 先介绍八数码问题 xff1a 我们首先从经典的八数码问题入手 xff0c 即对于八数码问题的任意一个排列是否有解 xff1f 有解的条件是什么 xff1f 我在网上搜了半天 xff0c 找到一个十分简洁的结论 八数码问题原始
  • 爬虫技术概览

    爬虫介绍 简介 自动化 半自动化从互联网上采集数据的程序 爬虫框架 一个简单的爬虫框架 外链图片转存失败 源站可能有防盗链机制 建议将图片保存下来直接上传 img 7ifdLU0V 1625273924704 http m qpic cn