App逆向学习笔记(三)——Android开发入门课

设备环境搭建

模拟器

官网:https://www.ldmnq.com/?n=6000

注:选择一个喜欢的版本安装即可,建议安装4版本,无所谓抓包问题

安装桥接工具

下载地址:https://www.androiddevtools.cn/

adb它是一个通用命令行工具,它可以做为Android与PC端连接的一个桥梁,所以adb又称为Android调试桥,用户可以通过adb在电脑上对Android设备进行全面操作,比如安装和调试应用,操作文件的传输等

参考地址:https://www.jianshu.com/p/0c0036b726ee

注: 工具安装成功,记得配环境变量

想买手机:刷面具root权限 系统是安卓10

复制代码
pixel4手机 解锁OEM 刷机安卓10 装面具 root
采购平台:闲鱼、淘宝 价格 500-600左右   老百姓陶吧

刷机教程

参考:https://blog.csdn.net/weixin_43846562/article/details/130028258

以pixel4为例,下载对应镜像文件 QQ2A.200405.005

查看版本号:https://source.android.com/docs/setup/reference/build-numbers

查看镜像文件:https://developers.google.com/android/images?hl=zh-cn#flame

下载驱动:https://developer.android.com/studio/run/oem-usb#Drivers

  • 执行脚本

手机连上电脑后, 执行解压后的images目录下的脚本

复制代码
进入fastboot模式  adb reboot bootloader
fastboot信息	   fastboot devices
ubuntu:  ./flash-all.sh
windows: 双击flash-all.bat

什么是bootloader模式?

在Android系统中,bootloader是指启动引导程序,它是手机系统启动的第一个程序,负责初始化硬件设备、加载内核、启动系统等重要工作。而bootloader模式则是指一种特殊的启动模式,通常用于修复系统故障、刷机等操作

  • 刷机完成

刷root权限:https://blog.csdn.net/blackblackblack223/article/details/137341966

查询已连接设备/模拟器

复制代码
adb devices

输出状态:

  • offline:表示设备未连接成功或无响应。
  • device:设备已连接,
  • no device:没有设备/模拟器连接

连接设备

常见模拟器端口

复制代码
夜神默认端口:62001/52001(adb connnect 127.0.0.1:62001)
mumu默认端口:7555
逍遥默认端口:21503
雷电默认端口:5555
腾讯默认端口:5555

 adb connect 设备ip(如:192.168.1.61)
  • 多个模拟器adb -s [ip地址:端口] shell

开启adb服务

复制代码
adb start-server

关闭adb服务,杀掉进程

复制代码
adb kill-server

重启手机

复制代码
adb shell reboot

查看android版本

复制代码
adb shell getprop ro.build.version.release
apk相关操作

安装apk

复制代码
adb install apk包名

卸载软件

复制代码
adb uninstall <软件名>   adb uninstall com.c2vl.kgamebox

导出导入操作

复制代码
adb pull <设备文件路径> [电脑存储路径]  | adb push <电脑文件路径> [设备存储路径]  		pull 下拉    push 推

强制暂停应用

复制代码
adb shell am force-stop packagename

清除应用数据与缓存

复制代码
adb shell pm clear (apk包名)

查询已安装包名列表

复制代码
adb shell pm list package

获取当前正在运行的activity(活动)

复制代码
 adb shell dumpsys window | findstr mCurrentFocus

查看运行的app包名

复制代码
adb shell am monitor
Android开发工具

地址:https://dl.google.com/android/android-sdk_r24.4.1-windows.zip

Android SDK(Software Development Kit)是为开发者提供的一组工具和资源,用于开发、测试和调试 Android 应用程序。它包含了开发 Android 应用所需的各种库、API、文档、样例代码和调试工具等。

Android SDK的主要组件包括:

  1. Android操作系统版本:SDK提供了各个Android版本的开发工具和平台文件,用于构建、测试和运行 Android 应用程序。
  2. Android命令行工具(Command-line Tools):包括 Android Debug Bridge(ADB)命令、Android 虚拟设备管理器(AVD Manager)命令、Android Package Manager(APK)打包工具等。
  3. Android 开发工具包(Android Development Tools,ADT)插件:用于在 Eclipse IDE 中进行 Android 应用程序的开发,并提供各种辅助功能,如布局编辑器、调试器等。不过需要注意的是,ADT 插件已经停止维护,推荐使用 Android Studio。
  4. Android Studio:这是官方推荐的 Android 开发环境(IDE),基于 IntelliJ IDEA 构建而成。Android Studio 提供了丰富的开发工具和集成的 Android SDK,能够更好地支持 Android 应用程序的开发、构建、调试和发布。
  5. Android 支持库(Support Library):提供了向后兼容的类和方法,以便在较旧版本的 Android 上使用新的特性和功能。

地址:https://developer.android.com/studio

参考:https://blog.csdn.net/weixin_44341110/article/details/131811275

参考:https://blog.csdn.net/zsyf33078/article/details/129422706

设置SDK
  1. 打开IDE进行设置

其中AndroidSDK Location一栏可单击右侧的Edit链接,进而选择SDK下载后的保存路径。

其下的三个选项卡默认显示SDKPlatforms,也就是各个SDK平台的版本列表,在此可下载各平台的开发包。

中间的选项卡SDKTools是工具管理界面,能够在线升级编译工具BuildTools、平台工具PlatformTools,以及开发者需要的其它工具。

设置Android Studio的Gradle

Gradle是一个构建工具,它是用来帮助我们构建app的,构建包括编译、打包等过程

Android应用程序开发中,Gradle通常被用来编译、构建和打包应用程序。Gradle 的构建脚本是基于 Groovy 和 Kotlin 语言编写的,这种脚本与 Maven POM 文件类似,但更加灵活、强大。

Gradle 可以与 Android SDK 配合使用,帮助您管理项目依赖、配置构建类型、处理资源等。Android Studio默认使用Gradle 作为构建工具,您可以通过Gradle 脚本文件(build.gradle)来配置和管理项目依赖、选择编译版本等。

在 Gradle 中,一个项目由多个模块组成,每个模块都有自己的构建脚本(build.gradle)。通常一个 Android应用程序由一个应用模块和多个库模块组成,这些模块可以互相依赖。

创建并编译App工程

1.创建新项目

打开AndroidStudio,依次选择菜单File→New→NewProject,弹出CreateNew Project窗口。

配置项目

项目创建后进入编辑界面

1、AndroidManifest.xml配置文件目录 ,如指明应用程序所需链接到的库的名称(除了默认的Android库之外)以及声明应用程序期望获得的各种权限,但manifest文件的主要功能仍然是向Android声明应用程序的组件

2、app/java这个目录是我们android项目核心代码 的存放地,MainActivity一般为创建一个Android工程时默认的主页面,ExampleInstrumentedTestExampleUnitTest是系统生成的测试类

3、app/res资源文件目录,这个目录里面用于存放我们安卓项目需要调用到的一些资源文件,其中包括布局文件和一些其他资源,如图片等等

4、Gradle Scripts gradle编译相关的脚本

  • build.gradle(Project)全局的gradle构建脚本,通常不需要进行修改

  • build.gradle(Module)是某个module对应的配置

  • gradle-wrapper.properties是为了告诉系统,如果我们的电脑上没有gradle工具,需要到哪个网址去下载

  • proguard-rules.pro是让我们自行添加混淆规则文件(相应module的目录下)

  • gradle.properties是用来配置构建属性

  • settings.gradle是配置项目包含的模块,通常情况下模块的引入都是自动完成的

  • local.properties是存储SDK/NDK的路径

运行App

选择模拟器或者真机最佳、自带虚拟模拟器10个G。

打包App

Build->Generate Signed Bundle/APK

构建签名文件

点击next往下

debug:调试模式

release:发布模式

apk文件和项目关系

找到编译之后的apk文件

arsc 文件就是一个资源索引表,它可以帮助系统根据资源ID快速找到资源

dex 文件就是源码文件

android开发基础

参考:https://zhuanlan.zhihu.com/p/628232942

Android是一种基于Linux是自由及开放源代码的操作系统,Android分为四个层,从高层到底层分别是应用程序层、应用程序框架层、系统运行库层和Linux内核层

Android四大组件

Android有四大基本组件:ActivityService服务、BroadcastReceiver广播接收器、Content Provider内容提供者

组件 描述
Activity(活动) 在应用中的一个Activity可以用来表示一个界面,意思可以理解为"活动",即一个活动开始,代表 Activity组件启动,活动结束,代表一个Activity的生命周期结束。一个Android应用必须通过Activity来运行和启动,Activity的生命周期交给系统统一管理。
Service(服务) Service它可以在后台执行长时间运行操作而没有用户界面的应用组件,不依赖任何用户界面,例如后台播放音乐,后台下载文件等。
Broadcast Receiver(广播接收器) 一个用于接收广播信息,并做出对应处理的组件。比如我们常见的系统广播:通知时区改变、电量低、用户改变了语言选项等。
Content Provider(内容提供者) 作为应用程序之间唯一的共享数据的途径,Content Provider主要的功能就是存储并检索数据以及向其他应用程序提供访问数据的接口。Android内置的许多数据都是使用Content Provider形式,供开发者调用的(如视频,音频,图片,通讯录等)
Activity

Activity是一个应用程序组件,提供一个屏幕,用户可以用来交互为了完成某项任务

Activity中所有操作都与用户密切相关,是一个负责与用户交互 的组件,可以通过setContentView(View)显示指定控件

在一个android应用中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应。Activity之间通过Intent进行通信

新建Activity文件

UI页面设计

复制代码
  <!---声明实现应用部分可视化界面的 Activity,必须使用 AndroidManifest 中的 <activity> 元素表示所有 Activity。系统不会识别和运行任何未进行声明的Activity。----->
        <activity  
            android:label="@string/app_name"  
            android:name="com.zj.wuaipojie.ui.MainActivity"  
            android:exported="true">  <!--当前Activity是否可以被另一个Application的组件启动:true允许被启动;false不允许被启动-->
            <!---指明这个activity可以以什么样的意图(intent)启动--->
            <intent-filter>  
                <!--表示activity作为一个什么动作启动,android.intent.action.MAIN表示作为主activity启动--->
                <action  
                    android:name="android.intent.action.MAIN" />  
                <!--这是action元素的额外类别信息,android.intent.category.LAUNCHER表示这个activity为当前应用程序优先级最高的Activity-->
                <category  
                    android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  

LinearLayout 线性布局

复制代码
android:orientation="vertical"
android:orientation="horizontal"

设置为vertical时,线性布局的子视图会垂直排列;

设置为horizontal时,线性布局的子视图会水平排列。

实操布局

Activity

复制代码
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // 调用父类的 onCreate 方法,确保了父类的初始化工作得以执行。
        super.onCreate(savedInstanceState);
        // setContentView  方法在安卓应用开发中用于设置当前活动(Activity)所使用的布局文件
        setContentView(R.layout.activity_main3);
    }
}

Activity文件介绍

复制代码
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity3">
  1. xmlns:tools="http://schemas.android.com/tools":这是在 XML 中声明一个命名空间(namespace),其中的 tools 是一个命名空间前缀,而 http://schemas.android.com/tools 则是该命名空间的 URI。在 Android 开发中,tools 命名空间通常用来定义一些在设计阶段使用的属性,例如预览时显示的提示信息、布局编辑时的辅助信息等。
  2. android:layout_width="match_parent":这是针对当前 View 的布局宽度进行设置,设置为match_parent表示该 View 的宽度将会填满其父容器的宽度。
  3. android:layout_height="match_parent":与上面类似,这是设置当前 View 的布局高度,也是设置为match_parent,表示该 View 的高度将会填满其父容器的高度。
  4. tools:context=".MainActivity3":这是利用 tools 命名空间中的属性 context,用来在设计阶段指定当前布局文件所关联的上下文(context)。在这里,.MainActivity3 表示该布局文件在设计阶段关联到 MainActivity3 这个 Activity。

button按钮

在Android开发中,Button(按钮)是用户界面中常用的交互元素,用于触发某些操作或事件。用户可以点击按钮来执行与该按钮相关联的操作。

以下是一些常用的Button属性和方法:

属性:

  • android:text:设置按钮上显示的文本。
  • android:background:设置按钮的背景。
  • android:onClick:指定按钮被点击时调用的方法。

常用方法:

  • setOnClickListener():为按钮设置点击监听器,当按钮被点击时触发相应的操作。
  • setText(String text):设置按钮上显示的文本内容。
  • setBackgroundColor(int color):设置按钮的背景颜色。

示例代码:

复制代码
<Button
    android:id="@+id/myButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Click me"
    android:onClick="onButtonClick" />

EditText文本框

在Android开发中,EditText是一个用于接收用户输入文本的常用控件。它允许用户在应用中键入和编辑文本内容。

以下是一些常用的EditText属性和方法:

属性:

  • android:hint:设置当EditText为空时显示的提示文本。
  • android:inputType:指定输入类型,例如文本、数字、密码等。
  • android:maxLength:限制输入的最大长度。
  • android:textColor:设置文本颜色。
  • android:background:设置背景。

常用方法:

  • getText():获取EditText中的文本内容。
  • setText(String text):设置EditText中的文本内容。
  • setHint(String hint):设置提示文本内容。

示例代码:

复制代码
<EditText
    android:id="@+id/editText"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Enter your name"
    android:inputType="text"
    android:maxLength="20" />

TextView文本

在Android中,文字展示框通常使用TextView控件来实现。TextView用于在用户界面中显示文本内容,但通常不允许用户进行编辑或输入。以下是一些常用的TextView属性和方法:

属性:

  • android:text:设置TextView中显示的文本内容。
  • android:textSize:设置文本的大小。
  • android:textColor:设置文本颜色。
  • android:gravity:设置文本的对齐方式(例如居中、靠左等)。
  • android:padding:设置文本与TextView边缘的间距。

常用方法:

  • setText(String text):设置TextView中显示的文本内容。
  • getText():获取TextView中的文本内容。
  • setTextSize(float size):设置文本的大小。
  • setTextColor(int color):设置文本颜色。

示例代码:

复制代码
<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello, this is a TextView"
    android:textSize="18sp"
    android:textColor="#000000"
    android:gravity="center" />

ImageView图片

ImageViewAndroid中的一个重要控件,用于显示图像。它可以显示来自资源文件、本地文件或者远程URL的图片。

以下是一些ImageView的主要特点和用法:

  1. 显示静态图片 : 可以通过设置src属性来显示静态图片,这可以是应用程序内的资源文件,也可以是网络上的图片地址。
  2. 显示动画 : 除了静态图片,ImageView也可以显示帧动画,通过设置src属性为动画资源,或者通过代码动态设置动画资源。
  3. 缩放类型 : 可以通过设置android:scaleType属性来控制图片的缩放方式,例如居中、拉伸、等比例缩放等。
  4. 交互功能 :ImageView也可以响应触摸事件,实现点击、长按等操作。
  5. 动态加载 : 通过编程方式,可以使用setImageResource()setImageBitmap()setImageDrawable()等方法来动态加载图片。

在布局文件中,可以这样使用ImageView

复制代码
<ImageView
    android:id="@+id/myImageView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/my_image"
    android:scaleType="centerCrop" />
2页面跳转

单位地址:https://blog.csdn.net/copy_yuan/article/details/51023566

两个Activity,两个XML文件之间使用Intent实现来回跳转

Intent是一种运行时绑定机制,它能在程序运行的过程中连接两个不同的组件。通过Intent,你的程序可以向Android表达某种请求或者意愿,Android会根据意愿的内容选择适当的组件来请求

首先我们要创建两个XML文件,分别取名为activity_main.xmlactivity_main2.xml

创建activity_main.xml

复制代码
<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        >
        <TextView
            android:id="@+id/tv1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="30sp"
            android:gravity="center"
            android:text="这里是第一页"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/btn1"
            android:textSize="30sp"
            android:layout_centerHorizontal="true"
            android:layout_below="@+id/tv1"
            android:text="点击我跳转到第二页"/>
    </RelativeLayout>

创建activity_main2.xml

复制代码
<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center">
        <TextView
            android:id="@+id/tv2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="30sp"
            android:gravity="center"
            android:text="这里是第二页"/>
        <Button
            android:id="@+id/btn2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/tv2"
            android:layout_centerHorizontal="true"
            android:textSize="30sp"
            android:text="点击返回第一页"/>
    </RelativeLayout>

activity文件编写

复制代码
Button button = this.findViewById(R.id.btn1);
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent(MainActivity.this,MainActivity2.class);
        startActivity(intent);
    }
});

创建了一个新的 Intent 对象,指定了从当前的 MainActivity 跳转到 MainActivity2 这个活动。然后通过 startActivity(intent) 方法启动了这个意图

复制代码
Button button = this.findViewById(R.id.btn2);
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        finish();
    }
});

当用户点击了某个 View 时,会调用 finish() 方法来关闭当前的 Activity,finish() 方法是 Activity类中的一个方法,用于结束当前的 Activity并将其从堆栈中移除。

点击搜索

搜索框

复制代码
<EditText
          android:id="@+id/editText1"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:hint="请输入搜索内容"
          android:inputType="text" />

点击框

复制代码
<Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="提交"
        />

Java逻辑编写

如果您想为 Button添加点击事件监听器(OnClickListener),您可以在代码中找到对应的 Button,并使用setOnClickListener方法来设置监听器。

复制代码
mEditText = findViewById(R.id.editText1);
Button button = findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // 在这里编写按钮点击事件的逻辑处理
        // 可以调用其他方法、更新UI等操作
          String text = mEditText.getText().toString();
          // Toast.makeText(XlActivity3.this, "点击功能实现", Toast.LENGTH_SHORT).show();
          Toast.makeText(XlActivity3.this, text, Toast.LENGTH_SHORT).show();
    }
});

Toast.LENGTH_SHORTAndroidToast消息显示的持续时间参数之一。当你在Android应用中使用Toast来展示短暂的消息时,可以设置消息显示的持续时间

ListView

ListView是一种常见的用户界面控件,用于在移动应用程序中展示大量数据。它能够以列表的形式显示数据,并且支持滚动和快速定位到特定条目。ListView 在移动应用开发中非常常见,特别是在 Android 平台上。

通过ListView,用户可以浏览大量文本、图像或其它类型的数据,而无需将所有内容都加载到屏幕上。这使得应用程序可以高效地处理大量数据,并提供良好的用户体验。

ListView通常与适配器(Adapter)一起使用,适配器负责将数据绑定到ListView上。通过适配器,可以将数据源中的数据转换为列表项,并在用户滚动时动态加载和显示新的列表项,从而实现高效的数据展示和管理。

复制代码
<ListView
          android:id="@+id/listView"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          />

<TextView
          android:id="@android:id/text1"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:textSize="18sp"
          android:textColor="@android:color/black" />

业务逻辑处理

获取了要显示的数据列表 dataList,那么你可以创建一个适配器来将它们绑定到 ListView上:

复制代码
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, dataList);
mListView.setAdapter(adapter);

BaseAdapterAndroid框架中的一个抽象类,用于实现自定义的适配器(Adapter),用于在 ListViewGridViewAdapterView 上展示数据。

适配器是连接数据和视图的桥梁,负责将数据源中的数据以适当的方式呈现到相应的视图上。BaseAdapter 提供了一种常见的适配器实现,封装了大部分适配器相关的操作,简化了开发者的工作。

使用 BaseAdapter,你可以根据自己的需求实现以下方法:

  1. getCount(): 返回适配器中数据项的个数。
  2. getItem(): 返回指定位置的数据项。
  3. getItemId(): 返回指定位置的数据项 ID。
  4. getView(): 创建并返回指定位置的视图,用于展示对应的数据项。

通过实现这些方法,你可以自定义数据载入、视图创建和数据绑定等操作,使得ListViewGridView在展示数据时符合你的需求。

适配器完整代码如下:

复制代码
// 继承BaseAdapter:MyAdapter类继承自BaseAdapter,这是Android中适配器类的基类,用于将数据与视图绑定在一起。
public class MyAdapter extends BaseAdapter {
	// 成员变量 mData:MyAdapter类包含一个名为mData的List<String>类型的成员变量,用于存储要展示的数据。
    private List<String> mData;
	// MyAdapter类有一个构造方法,接受一个List<String>类型的参数 data,用于初始化 mData 成员变量。
    public MyAdapter(List<String> data) {
        mData = data;
    }
	// mData中数据的数量,即列表项的个数。
    @Override
    public int getCount() {
        return mData.size();
    }
	// 根据位置返回对应的数据项。
    @Override
    public Object getItem(int position) {
        return mData.get(position);
    }
	// 返回指定位置的行ID,通常直接返回position。
    @Override
    public long getItemId(int position) {
        return position;
    }
	// 通过convertView参数 将数据填充到视图中,并返回给列表进行显示
    // 这里的position表示列表项在数据源中的位置,convertView表示当前可重用的视图对象,而parent表示列表的父容器。
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(parent.getContext())
                    .inflate(android.R.layout.simple_list_item_1, parent, false);
        }
        TextView textView = convertView.findViewById(android.R.id.text1);
        textView.setText(mData.get(position));
        return convertView;
    }
}

在上述代码中,我们创建了一个自定义的适配器 MyAdapter,继承自 BaseAdapter。适配器负责将数据绑定到 ListView上,并控制每个项的显示。

具体来说,我们在适配器中重写了几个方法,其中包括 getCountgetItemgetItemId,它们用于控制列表项的数量和内容。而 getView 方法则是用来创建和返回一个 View 对象,表示每个列表项的界面。

在 Activity 中使用适配器设置 ListView

复制代码
public class MainActivity extends AppCompatActivity {

    private ListView mListView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        List<String> data = new ArrayList<>();
        data.add("Item 1");
        data.add("Item 2");
        data.add("Item 3");

        mListView = findViewById(R.id.list_view);
        mListView.setAdapter(new MyAdapter(data));
    }
}
Service

Serviceandroid系统的四大组件之一,是一种长生命周期的,没有可视化界面,运行于后台的一种服务程序

BroadcastReceiver

BroadcastReceiver(广播接收器)是Android系统的四大组件之一,用于监听 / 接收 应用发出的广播消息,并做出响应

应用场景:不同组件之间通信(包括应用内 / 不同应用之间);与 Android 系统在特定情况下的通信(如当电话呼入时、网络可用时);多线程通信

Android广播分为两个角色:广播发送者、广播接收者

Content Provider

Content Provider主要的功能就是存储并检索数据以及向其他应用程序提供访问数据的接口

Android系统为一些常见的数据类型(如音乐、视频、图像、手机通信录联系人信息等)内置了一系列的Content Provider,这些都位于android.provider包下

安卓中的请求

OkHttp3 是一个开源的 Java/Android HTTP 客户端库,由Square 公司开发。它提供了简洁和高效的 API,用于进行 HTTP请求、处理响应以及与服务器进行通信。

以下是OkHttp3的一些主要特点和功能:

  1. 简单易用:OkHttp3 提供了简洁的 API,使得发送HTTP 请求变得简单和直观。它支持常见的 HTTP方法(GET、POST、PUT、DELETE等)和请求参数的设置,可以轻松构建出各种类型的请求。
  2. 高效性能:OkHttp3针对性能进行了优化,使用了连接池和请求复用等机制,减少了网络请求的延迟和资源消耗。它还支持 HTTP/2、SPDY和连接的压缩,提供更快的网络传输速度。
  3. 强大的拦截器:OkHttp3 提供了拦截器(Interceptor)机制,可以在发送请求和接收响应的过程中进行自定义的处理操作。你可以添加和配置多个拦截器,以实现日志记录、请求重试、请求头修改等功能。
  4. 支持异步请求:OkHttp3 支持发送异步请求,可以利用线程池并发地发送多个请求,从而提高请求的性能和吞吐量。同时,它还支持同步请求,即在当前线程中执行请求并等待返回结果。
  5. 文件上传和下载:OkHttp3 提供了方便的 API,用于实现文件的上传和下载功能。通过设置请求体和响应处理器,可以轻松地实现大文件的分块上传和断点续传等操作。
  6. 支持WebSocket:除了常见的 HTTP 请求,OkHttp3还支持使用WebSocket进行双向通信。它提供了WebSocket API,可以在应用程序中实现实时的消息推送和数据交互。
项目中使用

首先,在你的 Android项目中添加OkHttp3的依赖项。可以在build.gradle 文件中的dependencies块中添加以下代码:

复制代码
implementation 'com.squareup.okhttp3:okhttp:3.14.2' 
implementation 'com.squareup.okio:okio:1.17.4'  // 快速的访问、存储和处理你的数据
GET 请求样例

接下来,在你的Activity,可以编写以下代码发送GET请求:

复制代码
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {

    public OkHttpClient client = new OkHttpClient(); 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		
        
        // 创建请求对象
        Request request = new Request.Builder()
            .url("https://api.example.com/data") // 设置请求的 URL
            .build();
        
        // 发送请求
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // 请求失败,处理错误
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                // 请求成功,处理响应数据
                if (response.isSuccessful()) {
                    String responseData = response.body().string();
                    // 在这里处理响应数据
                } else {
                    // 请求失败,处理错误
                    // 可以根据 response.code() 判断具体的失败原因
                }
            }
        });
    }
}

在上述代码中,首先创建了一个 OkHttpClient对象,用于发送 HTTP请求。然后,创建一个 Request对象,并设置请求的 URL

接下来,通过 client.newCall(request).enqueue() 方法发送异步请求。在 enqueue() 方法中,传入一个 Callback 对象用于处理请求的响应。

在 Callback 的 onResponse() 方法中,首先检查响应是否成功(使用 response.isSuccessful() 判断)。如果成功,可以通过 response.body().string() 获取响应的数据。如果失败,可以根据 response.code() 判断具体的失败原因。

以上就是一个简单的 OkHttp3 请求示例,在实际开发中,你可以根据需要设置更多的请求参数,并使用其他方法(如 POST、PUT 等)发送不同类型的请求。记得在AndroidManifest.xml文件中添加网络访问权限:

复制代码
<uses-permission android:name="android.permission.INTERNET" />

同时要注意,在 Android 开发中不能在主线程中进行网络请求,避免阻塞界面操作,可以使用异步请求或者使用 AsyncTask等工具来执行网络请求。

POST请求样例

29版本之后访问http协议需要配置

出现以下异常:

复制代码
java.net.UnknownServiceException: CLEARTEXT communication to www.httpbin.org not permitted by network

原因:Android P(API级别29) 是默认禁止访问http的API的。

解决办法:

首先在配置清单文件中加入:

复制代码
<application
       	...
        android:networkSecurityConfig="@xml/network_security_config"
        android:theme="@style/Theme.Xl1109">

之后在res目录下,创建xml文件名字为network_security_config

复制代码
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

Post请求与Get请求不同的地方在于Request.Builderpost()方法,post()方法需要一个RequestBody的对象作为参数

复制代码
public void MyPost(String url,String key,String value){
    	// 创建请求体  参数
        FormBody body = new FormBody.Builder()
                .add(key,value)
                .build();
    	 // 创建请求对象  头部
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
    	// 发起请求
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //...
                // 请求失败,处理错误
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if(response.isSuccessful()){
                    String result = response.body().string();
                    Log.d(TAG, "onResponse: " + result);
                    //处理UI需要切换到UI线程处理
                }
            }
        });
    }

POST请求携带json格式

JSONObjectorg.json库中的一个类,表示 JSON 格式的对象。使用 JSONObject,可以方便地创建、解析和操作 JSON对象。

复制代码
public void MyPostJson(String url) {
        // 创建请求参数的 JSON 对象
        JSONObject json = new JSONObject();
        try {
            json.put("kw", "python");

        } catch (JSONException e) {
            e.printStackTrace();
        }
        // 创建请求体
        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(mediaType, json.toString());
        // 创建请求对象
        Request request = new Request.Builder()
                .url(url) // 设置请求的 URL
                .post(body) // 设置请求的方法为 POST,并设置请求体
                .build();

        // 发送请求
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //...
                // 请求失败,处理错误
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if(response.isSuccessful()){
                    String result = response.body().string();
                    Log.d(TAG, "onResponseJson: " + result);
                    //处理UI需要切换到UI线程处理
                }
            }
        });
    }
实战对接搜索爬虫

背景:针对所学知识、编写一个爬虫展示页面,实现如下功能,输入页码能对数据进行实时采集展示

先设计UI页面

UI页面需要先设计搜索框、提交按钮框、数据展示框

复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".XlActivity3">

    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入搜索页码"
        android:inputType="text" />

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="提交"
     />

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

    <TextView
        android:id="@+id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textColor="@android:color/black" />

</LinearLayout>
Activity页面设计
复制代码
public class XlActivity3 extends AppCompatActivity {

    private static final String TAG = "OkHttpDemo";

    private EditText mEditText;
    private ListView mListView;
    private Button mButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_xl3);

        mEditText = findViewById(R.id.editText1);
        mButton =  findViewById(R.id.button1);
        mListView = findViewById(R.id.listView);

        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String text = mEditText.getText().toString();
                Toast.makeText(XlActivity3.this, text, Toast.LENGTH_SHORT).show();
                sendRequestWithOkHttp(text); //点击button按钮使用sendRequestWithOkHttp()方法
            }

            private void sendRequestWithOkHttp(String pages) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            OkHttpClient client = new OkHttpClient();//创建一个OkHttpClient实例
                            //想要发起一条Http请求,需要创建一个Request对象
                            RequestBody body = new FormBody.Builder()
                                    .add("column", "szse_gem_latest")
                                    .add("pageNum", pages)
                                    .add("pageSize", "30")
                                    .add("sortName", "")
                                    .add("sortType", "")
                                    .add("clusterFlag", "true")
                                    .build();

                            // 创建请求对象
                            Request request = new Request.Builder()
                                    .url("http://www.cninfo.com.cn/new/disclosure") // 设置请求的 URL
                                    .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36") // 设置头部信息
                                    .addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
                                    .post(body) // 设置请求的方法为 POST,并设置请求体
                                    .build();

                            client.newCall(request).enqueue(new Callback() {
                                @Override
                                public void onFailure(Call call, IOException e) {
                                    //...
                                    // 请求失败,处理错误
                                    e.printStackTrace();
                                }

                                @Override
                                public void onResponse(Call call, Response response) throws IOException {
                                    if(response.isSuccessful()){
                                        try {
                                            String result = response.body().string();
                                            // 很对json操作需要处理异常 否则会爆红
                                            JSONObject jsonObject = new JSONObject(result);
                                            JSONArray  classifiedAnnouncements = jsonObject.getJSONArray("classifiedAnnouncements");

                                            List<String> data = new ArrayList<>();

                                            // 遍历 jsonArray 获取数组中的每个值
                                            for (int i = 0; i < classifiedAnnouncements.length(); i++) {
                                                String value = classifiedAnnouncements.getString(i);
                                                // 使用获取到的值进行后续操作
                                                JSONArray jsonArray = new JSONArray(value);
                                                JSONObject resValue = jsonArray.getJSONObject(0);

                                                String announcementTitle = resValue.getString("announcementTitle");
                                                data.add("data:" + announcementTitle);

                                            }
//                                            Log.d(TAG, "onResponse: " + classifiedAnnouncements);

                                            //将服务器返回的数据进行读取,并将结果传入到showResponse()方法中
                                            //处理UI需要切换到UI线程处理
                                            showResponse(data);
                                        } catch (JSONException e) {
                                            e.printStackTrace();
                                        }

                                    }
                                }

                            });

                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                    private void showResponse(final List responseData) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                //将结果显示到界面上
                                mListView.setAdapter(new MyAdapter(responseData));
                            }
                        });
                    }
                }).start();
            }

        });
    }
}
BaseAdaper适配器
复制代码
package com.luoge.couse01;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;


public class MyAdapter extends BaseAdapter {
    private List<String> mData;

    public MyAdapter(List<String> data) {
        mData = data;
    }
    @Override
    public int getCount() {
        // 返回总共的数据项数,这里指定为每页展示多少条数据
        return mData.size();
    }

    @Override
    public Object getItem(int position) {
        // 返回指定位置的数据项
        return mData.get(position);
    }

    @Override
    public long getItemId(int position) {
        // 返回指定位置的数据项 ID,这里我们简单地返回了其位置值
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
        }
        TextView textView = convertView.findViewById(android.R.id.text1);
        textView.setText(mData.get(position));
        return convertView;
    }
}

Java爬虫

一、简介

HttpClientApache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。HttpClient已经应用在很多的项目中,比如Apache Jakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClient。

下载地址: http://hc.apache.org/downloads.cgi

二、使用方法

使用HttpClient发送请求、接收响应很简单,一般需要如下几步即可。

  1. 创建HttpClient对象。
  2. 创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
  3. 如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。
  4. 调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse
  5. 调用HttpResponsegetAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponsegetEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
  6. 释放连接。无论执行方法是否成功,都必须释放连接
三、请求样例
GET请求
复制代码
HttpGet httpGet = new HttpGet("https://www.baidu.com");

public static void getTest() throws  IOException{
    // 1. 创建HttpClient实例
    CloseableHttpClient httpClient = HttpClients.createDefault();
    // 2. 创建GET请求方法实例
    HttpGet httpGet = new HttpGet("https://www.baidu.com");
    // 3. 调用HttpClient实例来执行GET请求方法,得到response
    CloseableHttpResponse response = httpClient.execute(httpGet);
    // 4. 读response,判断是否访问成功 2xx表示 成功。
    int status = response.getStatusLine().getStatusCode();
    if (status >= 200 && status < 300) {
        // 调用response.getEntity()时,它会返回一个HttpEntity对象,你可以通过这个对象来访问和处理HTTP响应的实体内容
        HttpEntity entity = response.getEntity();
        System.out.println(response);
        System.out.println("=======================");
        String html = EntityUtils.toString(entity,"utf-8");
        System.out.println(html);
    } else {
        throw new ClientProtocolException("Unexpected response status: " + status);
    }
    // 5. 释放连接
    response.close();
    httpClient.close();
}

在 Java 中,ResponseHandler 是 HttpClient 中的一个接口,用于处理 HTTP 请求的响应

复制代码
    public static void getTests1(){

        HttpGet httpGet = new HttpGet("http://www.example.com");
        ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
            @Override
            public String handleResponse(HttpResponse httpResponse) throws ClientProtocolException, IOException {

                int status = httpResponse.getStatusLine().getStatusCode();
                if (status >= 200 && status < 300) {
                    return EntityUtils.toString(httpResponse.getEntity());
                } else {
                    throw new IOException("Unexpected response status: " + status);
                }

            }

        };
        try {
            String responseBody = httpClient.execute(httpGet, responseHandler);
            System.out.println(responseBody);
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

创建了一个 HttpClient 实例,然后创建一个 HttpGet 请求对象来请求指定的 URL。接下来,我们定义了一个匿名内部类实现 ResponseHandler<String> 接口,并重写了 handleResponse 方法来处理 HTTP 响应。最后,我们使用 httpClient.execute 方法并传入 httpGet 请求对象和 responseHandler 来执行 HTTP 请求,并处理返回的响应数据。

POST请求
复制代码
HttpPost httpPost = new HttpPost("http://httpbin.org/post");

public static void postTest() throws IOException{
    // 2. 创建HttpPost实例
    HttpPost httpPost = new HttpPost("http://httpbin.org/post");
    httpPost.setEntity(new StringEntity("this is Post"));
    // 3. 调用HttpClient实例来执行HttpPost实例
    CloseableHttpResponse response = httpClient.execute(httpPost);
    // 4. 读 response
    int status = response.getStatusLine().getStatusCode();
    if (status >= 200 && status < 300) {
        HttpEntity entity = response.getEntity();
        System.out.println(response);
        System.out.println("===================");
        String html = EntityUtils.toString(entity);
        System.out.println(html);
    } else {
        throw new ClientProtocolException("Unexpected response status: " + status);
    }
    // 5. 释放连接
    response.close();
    httpClient.close();
}

这段代码是用来发送一个简单的HTTP POST请求,并获取并输出响应内容的。让我来解释一下其中的各个部分:

  1. 创建HttpPost实例:

    复制代码
    HttpPost httpPost = new HttpPost("http://httpbin.org/post");

    在这里,首先创建了一个HttpPost实例,指定了要发送 POST 请求的目标 URL,这里使用了"http://httpbin.org/post"作为示例目标地址。

  2. 设置请求实体:

    复制代码
    httpPost.setEntity(new StringEntity("this is Post"));

    使用setEntity方法将请求的实体内容设置为一个包含字符串"this is Post"StringEntity。这意味着在发送POST请求时,会将这个字符串作为请求的主体内容发送给目标 URL

  3. 执行请求并获取响应:

    复制代码
    CloseableHttpResponse response = httpClient.execute(httpPost);

    通过调用httpClient.execute(httpPost)来执行HttpPost实例,发送POST请求并获取服务器的响应结果。

  4. 处理响应:

    复制代码
    int status = response.getStatusLine().getStatusCode();
    if (status >= 200 && status < 300) {
        // 处理成功的情况
        HttpEntity entity = response.getEntity();
        System.out.println(response);
        System.out.println("===================");
        String html = EntityUtils.toString(entity);
        System.out.println(html);
    } else {
        // 处理失败的情况
        throw new ClientProtocolException("Unexpected response status: " + status);
    }

    首先通过response.getStatusLine().getStatusCode()获取响应的状态码,然后判断状态码是否在200到299之间,表示请求成功。如果是成功的状态码,就从响应中获取实体内容并打印出来;否则抛出异常。

  5. 释放连接:

    复制代码
    response.close();
    httpClient.close();

    最后,在处理完响应后,需要关闭响应对象和HttpClient实例,释放连接资源。

算法逆向实战

NoSuchAlgorithmException 是一个 Java 异常类,它表示请求的加密算法在当前环境中不可用或不存在。

复制代码
public static String md5(String input) {
        try {
            // 使用 MD5 算法创建 MessageDigest 对象
            MessageDigest md = MessageDigest.getInstance("MD5");
             // 对更新后的数据计算哈希值,存储在 byte 数组中
            byte[] messageDigest = md.digest(input.getBytes());
            // 将 byte 数组转换为十六进制字符串
            StringBuilder hexString = new StringBuilder();
            for (byte b : messageDigest) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            // 返回十六进制字符串
            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

代码注解

复制代码
for (byte b : messageDigest) {
    String hex = Integer.toHexString(0xff & b);
    if (hex.length() == 1) {
    hexString.append('0');
    }
    hexString.append(hex);
}
  1. for (byte b : messageDigest):这是一个增强型 for 循环,用于遍历 messageDigest 字节数组中的每个字节。
  2. String hex = Integer.toHexString(0xff & b);:对每个字节进行位运算和转换,得到对应的十六进制字符串。首先,0xff & b 是一个位运算,它会将 b 转换为无符号整数(即使 b 是负数),然后将结果转换为十六进制字符串。
  3. if (hex.length() == 1) { hexString.append('0'); }:如果转换得到的十六进制字符串的长度为 1,也就是只有一位,那么在该字符串前面加上一个 '0',保证每个字节的十六进制表示都是两位。
  4. hexString.append(hex);:将经过处理的十六进制字符串添加到 hexString 中,最终得到完整的十六进制表示的结果。

Java爬虫

Jsoup解析

官网:https://jsoup.org/download

Jsoup是一款基于Java的HTML解析器,它可以方便地从网页中抓取和解析数据。它的主要作用是帮助开发者处理HTML文档,提取所需的数据或信息。下面介绍几个常用的API:

  • 选择器(Selector)API:用于根据CSS选择器语法选择HTML元素。
  • 属性(Attribute)API:用于获取、设置和移除HTML元素的属性。
  • 遍历(Traversal)API:用于遍历HTML文档中的元素。
  • 操作(Manipulation)API:用于修改HTML文档中的元素和属性。
选择器(Selector)API

选择器API允许您使用CSS选择器语法选择HTML元素。它提供了一些方法,如Document.select()Elements.select(),可用于选择HTML元素。

复制代码
// 根据CSS选择器选择所有li元素
Elements elements = doc.select("li");
 
// 选择所有class属性为news的div元素
Elements divs = doc.select("div.news");
 
// 选择id属性为header的div元素
Element header = doc.select("div#header").first();

实操提取时间数据

复制代码
Elements elements = doc.select("span.state5");
    for (Element movie : elements) {
    String title = movie.text();
    System.out.println(title);
}
属性(Attribute)API

属性API用于获取、设置和移除HTML元素的属性。可以使用Element.attr()方法获取或设置单个属性的值,或使用Element.attributes()方法获取所有属性。

复制代码
// 获取元素的属性值
String href = element.attr("href");
 
// 设置元素的属性值
element.attr("href", "http://example.com");
 
// 移除元素的属性
element.removeAttr("href");
 
// 获取元素的所有属性
Attributes attributes = element.attributes();

// 选择所有href属性以"http"开头的a元素
Elements links = doc.select("a[href^=http]");
 
// 选择所有class属性包含news的div元素
Elements divs = doc.select("div[class~=news]");
遍历(Traversal)API

遍历API用于遍历HTML文档中的元素。可以使用Element.parent()Element.children()Element.nextElementSibling()等方法遍历HTML文档中的元素。

复制代码
// 获取元素的父元素
Element parentElement = element.parent();
 
// 获取元素的子元素
Elements childrenElements = element.children();
 
// 获取元素的下一个兄弟元素
Element nextSiblingElement = element.nextElementSibling();
操作(Manipulation)API

操作API用于修改HTML文档中的元素和属性。可以使用Element.html()Element.text()Element.append()等方法操作HTML文档中的元素和属性。

复制代码
// 获取元素的HTML内容
String html = element.html();
 
// 获取元素的文本内容
String text = element.text();
 
// 向元素中追加HTML内容
element.append("<p>这是一个新段落</p>");
 
// 向元素中追加文本内容
element.appendText("这是一段新文本");
组合选择器

组合选择器是指将多个选择器组合在一起,常用的组合选择器有空格、大于号、加号等。例如:

复制代码
// 选择所有div元素内的p元素
Elements paragraphs = doc.select("div p");
 
// 选择所有直接子元素是div的p元素
Elements directParagraphs = doc.select("div > p");
读取文件
复制代码
File input = new File("D:\\works\\out_codes\\javas\\learn\\untitled\\src\\spider\\dom.html");
Document doc = Jsoup.parse(input, "UTF-8");
对接MySQL

jar包地址:https://mvnrepository.com/artifact/mysql/mysql-connector-java

查看自己MySQL版本

测试code提交

复制代码
 public static void dbSave(){
        String url = "jdbc:mysql://localhost:3306/spiderjava";
        String username = "root";
        String password = "123456";
        try {
            Connection connection = DriverManager.getConnection(url, username, password);
            String sql = "INSERT INTO test (id, title, text, times) VALUES (?, ?, ?, ?)";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, "431179");
            preparedStatement.setString(2, "方便进还是不方便进");
            preparedStatement.setString(3, "等待回复:18天17小时14分");
            preparedStatement.setString(4, "2023-11-19 17:43:06");
            preparedStatement.executeUpdate();
            // 关闭数据库连接
            connection.close();
        } catch (SQLException e){
            e.printStackTrace();
        }
    }

DriverManager.getConnection(url, username, password)方法建立与MySQL数据库的连接,并将连接对象赋值给connection变量。

connection.prepareStatement(sql)方法创建一个PreparedStatement对象,并将SQL语句传递给它。

多线程爬虫

Executors类 提供工厂方法用来创建不同类型的线程池。Executors是工具类,他提供对ThreadPoolExecutor的封装,会产生几种线程池供大家使用。

线程池demo

复制代码
package spider;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Spd {
    public static void gets(int page) {
        System.out.println(page);
    }
}

public class MultiThreadExample {
    public static void main(String[] args) {
        // 创建固定大小的线程池,包含5个线程
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        long startTime = System.currentTimeMillis();
        // 提交10个任务给线程池执行
        for (int i = 1; i <= 100; i++) {
            final int page = i; // 需要使用 final 或 effectively final 的变量
            executorService.submit(() -> Spd.gets(page));
        }
        long endTime = System.currentTimeMillis();
        long executionTime = endTime - startTime;

        System.out.println("Total execution time: " + executionTime + " milliseconds");

        // 关闭线程池
        executorService.shutdown();
    }
}

线程池提交任务写法

复制代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public static void getTest() {
        // 创建固定大小的线程池
        String base_url = "https://wzzdg.sun0769.com/political/index/politicsNewest";
    	 // 1、使用工厂类------获取线程池对象
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 1; i < 20; i++) {
            final int page = i; // 使用final修饰符声明不可变的局部变量
            System.out.println("开始第几页:" + page); // 打印当前页数
            // 提交任务给线程池执行
            executorService.submit(() -> {
                try {
                    String url = base_url + "?id=1&page=" + page;
                    // 执行爬取逻辑
                    String content = crawl(url);
                    // 处理爬取结果
                    process(content);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
        // 关闭线程池
        executorService.shutdown();
    }

异步线程执行

复制代码
public static void getTest() {
    ExecutorService executorService = Executors.newFixedThreadPool(5);

    for (int i = 1; i < 20; i++) {
        final int page = i;
        System.out.println("开始第几页:" + page);

        CompletableFuture.runAsync(() -> {
            try {
                String url = BASE_URL + "?id=1&page=" + page;
                String content = crawl(url);
                process(content);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, executorService);
    }

    executorService.shutdown();
}
json库使用

JSONObject是一种在Java中表示JSON对象的数据结构。它是一个无序的键值对集合,用花括号({})包围,并且每个键值对由冒号(:)分隔。

创建JSONObject:

复制代码
JSONObject jsonObject = new JSONObject();

添加键值对到JSONObject:

复制代码
jsonObject.put("key1", "value1");
jsonObject.put("key2", 123);
jsonObject.put("key3", true);
// 可以添加其他JSONObject或JSONArray作为值

获取JSONObject中指定键的值:

复制代码
Object value = jsonObject.get("key");

获取JSONObject中所有键的集合:

复制代码
Set<String> keys = jsonObject.keySet();

遍历JSONObject中的所有键值对:

复制代码
for (String key : jsonObject.keySet()) {
    Object value = jsonObject.get(key);
    // 处理每个键值对
}

**JSONArray**是一种在Java中表示JSON数组的数据结构。它是在一对方括号([])内包含零个或多个JSON值的有序集合。JSONArray可以包含不同类型的值,例如字符串、数字、布尔值、对象或其他数组

创建JSONArray:

复制代码
JSONArray jsonArray = new JSONArray();

添加元素到JSONArray:

复制代码
jsonArray.put("value1");
jsonArray.put(123);
jsonArray.put(true);

获取JSONArray的长度(元素个数):

复制代码
int length = jsonArray.length();

获取JSONArray中指定位置的元素:

复制代码
Object element = jsonArray.get(index);

遍历JSONArray中的所有元素:

复制代码
for (Object elements : jsonArray) {
    // 处理每个元素
    System.out.println(elements);
}
相关推荐
handler012 小时前
拒绝权限报错!三分钟掌握 Linux 权限管理
linux·c语言·c++·笔记·学习
安卓机器3 小时前
rom定制系列------魅族16x 解锁bl root与Flyme9安卓10线刷固件 传感器修复
android·魅族16x玩机
阿Y加油吧3 小时前
算法实战笔记:LeetCode 169 多数元素 & 75 颜色分类
笔记·算法·leetcode
ouliten3 小时前
cuda编程笔记(39)--Asynchronous Barriers(异步屏障)
笔记·cuda
U盘失踪了3 小时前
Go 结构体
笔记·golang
wellc5 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
CYY955 小时前
Android 打印 SO 库的异常日志
android
xuhaoyu_cpp_java6 小时前
连接池学习
数据库·经验分享·笔记·学习