5

爬虫入门概念与硬核实战巩固(一)

 2 years ago
source link: https://blog.csdn.net/HG0724/article/details/115796050
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client



  1. 你是否在夜深人静的时候,想看一些会让你更睡不着的图片却苦于没有资源…
  2. 你是否在节假日出行高峰的时候,想快速抢购火车票成功…
  3. 你是否在网上购物的时候,想快速且精准的定位到口碑质量最好的商品…

本章节所有感悟来自:Python爬虫7天速成(2020全新合集)无私分享 Python
视频是2020年,我是2021年看得视频,网站的更新速度较快,其中2.6章节中的药品监督总局网址已经不是视频中的网址我已经做个笔记和更改,希望帮助到想学习爬虫的你们


一、爬虫是什么?

  • 通过编写程序、模拟浏览器上网,然后让其模拟浏览器去上网,然后让其去互联网上抓取数据的过程。
  • 可以认为浏览器上网就是一个原始的、天然的爬虫工具。

爬虫的两种方式

  • 爬虫的价值
    在这里插入图片描述
  • 爬虫究竟是合法的还是违法的?
  1. 在法律中是不被禁止的
  2. 具有违法风险
  3. 善意爬虫 恶意爬虫
  • 爬虫带来的风险可以体现再如下两个方面:
  1. 爬虫干扰了别访问网站的正常运营
  2. 爬虫抓取了受到法律保护的特定类型的数据或信息
  • 如何在使用编写爬虫的过程中避免进入‘橘子’的厄运呢?
  1. 时常的优化自己的程序,避免干扰被访问网站的正常运行
  2. 在使用,传播爬取到二到数据时,审查抓取到的内容,如果发现了涉及到用户隐私或者商业机密等敏感内容,需要及时停止爬取或传播
  • 爬虫在使用场景中的分类
  • 通用爬虫
    抓取系统重要组成部分。抓取的是一整张页面数据
  • 聚焦爬虫
    是建立在通用爬虫的基础之上。抓取的是页面中特定的局部内容。
  • 增量式爬虫
    检测网站中数据更新的情况。只会抓取网站中最新更新出来的数据。
  • 爬虫的矛与盾
  • 反爬机制
    相关的门户网站,可以指定相应的策略或者技术手段,防止爬虫程序进行网站数据的爬取。
  • 反反爬策略
    爬虫程序可以通过制定相关的策略或者技术手段,破解门户网站中具备的反爬机制,从而可以获取门户网站中相关的数据。

1.1 robots.txt

  • robots.txt协议

其实就是一项君子协议
此协议就规定了网站哪些数据可以被爬虫爬取,哪些数据不可以被爬虫爬取。
既可以保护网站隐私数据,又可以被搜索引擎收录,增加相关网站的流量。

  • robots.txt协议展示
    在这里插入图片描述

1.2 http

超文本传输协议

  • http协议

概念:就是服务器客户端进行数据交互的一种形式。

  • 常用请求头信息
  • User-Agent:请求载体的身份标识
    例如:1. 使用Google浏览器浏览一个网址,则Google浏览器的身份就是当前载体的身份标识,这个身份标识即可以使用一个字符串来表示。2. 若是使用编写代码方式发起一个url的请求则标识就不是上述字符串
  • Connection:请求完毕之后,是断开连接还是保持连接
  1. close
  2. keep live
  • 常用响应头信息
  • Content-Type:服务器响应回客户端的数据类型
    可以是字符串、Json等

1.3 https

http是安全的,https是不安全的额
安全的超文本传输协议,数据传输和交互的时候是经过加密的

  1. 对称密钥加密

客户端需要把发送给服务器的数据进行加密(加密方式是由客户端自己指定的),然后传输密文和解密的密钥给服务器,服务器接收后可以根据密钥对密文进行解密,解密之后,服务器就可拿到原始数据
分析:若密文和密钥被拦截,则密文就会被密钥解密,数据就会被暴露。

在这里插入图片描述

  1. 非对称密钥加密

在这里插入图片描述

  1. 证书密钥加密

https所采用的密钥加密就是该方式

在这里插入图片描述


二、request模块

2.1 网络请求requests

  • urllib模块 (古老的模块)
  • request模块⭐(重点学习)

request模块:python中原生的一款基于网络请求的模块,功能非常强大,简单便捷,效率极高。
作用模拟浏览器发送请求。

  • 如何使用?(reqests模块的编码流程)⭐

一定要严格遵从浏览器发送请求流程:

  1. 指定url(具体网址)
  2. 发起请求(类似浏览器地址栏输入网址按下回车–GET请求)
  3. 获取相应数据(回车之后,浏览器会有一页数据)
  4. 持久化存储–响应数据(request模块在互联网上爬取的页面数据)

pip install requests

2.2 实战巩固⭐

在这里插入图片描述

2.1 ruquests第一血

  • 爬取搜狗首页的页面数据
import  requests 

if __name__ == "__main__":
    # 1. 指定url
    url = "https://www.sogo.com/"
    # 2. 发起请求  
    response = requests.get(url=url) 
    # get方法灰返回一个响应对象
    # 3. 获取相应数据 .text返回的是字符串形式的响应数据
    page_text = response.text
    print(page_text)
    # 4. 持久化存储 --page_text
    with open('./sogo.html', 'w',encoding='utf-8') as fp:
        fp.write(page_text)
    print('爬取数据结束')

在这里插入图片描述

2.2 简易网页采集器

爬取搜狗指定词条对应的都多结果页面

在这里插入图片描述

# 反爬机制:UA检测
# UA检测对应的反反爬策略:#UA伪装


# UA:User-Agent(请求载体的身份标识)
'''
UA检测:门户网站的服务器会检测对应请求的载体身份标识,如果检测到请求的载体身份标识是某一款浏览器,
        那么就说明该请求是一个正常的请求。但是,如果检测到请求的载体身份标识不是基于某一款浏览器的,
        则表示该请求为不正常的请求(爬虫),z则服务器端就很有可能拒绝该次请求
'''

#UA伪装:让爬虫对应的请求载体身份标识伪装成一款浏览器
import requests

if __name__ == '__main__':
    #UA伪装:将对应的User-Agent封装到一个字典中
    # 伪装成Google浏览器
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36'
    }

    # 1. 指定url
    url = 'https://www.sogou.com/sogou?'
    # 'https://www.sogou.com/sogou?query=波晓张'这样也可以的 
    # 处理url携带的参数  通常情况url不可能只携带一组参数
    # 处理:封装到字典中
    key = input('enter a word:')
    param = {
        'query':key
    }
    
    # 2. 对指定的url发起请求 对应的url是携带参数的,并且请求过程中处理了参数
    response = requests.get(url,params=param,headers=headers)

    # 3. 获取响应数据
    page_txt = response.text

    filename = key+'.html'
    with open(filename,'w',encoding='utf-8') as fp:
        fp.write(page_txt)
    print(filename,'保存成功!!!')

在这里插入图片描述

在这里插入图片描述

  • 出现问题
    在这里插入图片描述
    在这里插入图片描述
    1. 解决乱码问题
      在这里插入图片描述
      在这里插入图片描述

处理乱码后,页面显示【异常访问请求】导致请求数据的缺失

  • 异常访问的请求
    • 网站后台已经检测出该次请求不是通过浏览器发起的请求而是通过爬虫程序发起的请求(不是浏览器发起的请求都是异常请求

2.3 破解百度翻译

录入单词之后,没有触碰任何的点击事件。当前页面就变化了,也就是进行了局部刷新(AJAX请求

  • 下图是录入数据前后对比:
    在这里插入图片描述
    在这里插入图片描述
  • 什么是 AJAX ?

通过浏览器抓包(F12)了解到:

  • 对应请求为POST请求(携带了参数)
  • 响应数据是一组json数据
import requests
import json

if __name__ == '__main__':
    # 1. 指定url
    # post请求
    post_url = 'https://fanyi.baidu.com/sug'

    # 2. 进行UA伪装
    headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36'
}
    # 3. post请求参数处理(同get)
    word = input('enter a word:')
    data = {
        'kw':word
    }
    # 4. 请求发送
    respose = requests.post(url=post_url,data=data,headers=headers)

    # 5. 获取响应数据 由浏览器抓包工具可知返回的是json数据
    # 此处若用respose.text  则返回的是字符串
    # print("text",respose.text)
    dic_obj = respose.json()# json()方法返回的是obj(如果确认响应数据是json类型,才可以使用json())
    # print("dic_obj",dic_obj)

    # 6. 持久化存储
    filename = word+'.json'
    fp = open(filename,'w',encoding='utf-8')
    json.dump(dic_obj,fp=fp,ensure_ascii=False) ①# 拿到的json字符串是不能用ASCII进行编码的

    print('over!!!')

在这里插入图片描述
在这里插入图片描述

2.4 爬取豆瓣带你应分类排行榜中电影详情数据 ⭐

如上图搜索并点击进入相应内容,进入相应页面后可以点击类型:喜剧,之后通过滑动滚轮后发现滑动到底部后发现:

  1. 地址栏没有发生变化
  2. 右边的矩形灰色栏一到底部,底部就会出现新的电影数据而且矩形灰色栏回跳动到中间位置

因此,我们判断滚轮滑动到底部,页面进行了AJAX请求

在这里插入图片描述

思考:基于抓包工具进行全局搜索不一定可以每次都能定位到动态加载数据对应的数据包?
原因:如果动态加载的数据是经过加密的密文数据

import requests
import json

if __name__ == '__main__':
    url = 'https://movie.douban.com/j/chart/top_list'

    param = {
        'type': '24',
        'interval_id': '100:90',
       ' action': '',
        'start': '0', # 从库中第几部电影去取
        'limit': '20', # 第一次取出的个数
    }

    headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36'
}
    # 根据浏览器抓包工具进行请求类型判断
    response = requests.get(url=url,params = param,headers = headers)
    
    # 由浏览器判断返回类型是列表 
    list_data = response.json()①
    fp = open('./douban.json','w',encoding='utf8')
    json.dump(list_data,fp,ensure_ascii=False)

    print('over!!!')

在这里插入图片描述

2.5 爬取肯德基餐厅查询中指定地点的餐厅数据

肯德基官网

    1. 前期分析
      在这里插入图片描述

同理,进入地址搜索栏后,输入地址若地址栏没有发生变化则页面是进行的AJAX请求,反之则不是AJAX请求

在这里插入图片描述
在这里插入图片描述

结论:该页面发生了AJAX请求

  • 爬取一页数据的代码
import requests

if __name__ == '__main__':

    # 爬取的是第一页数据
    url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'

    data = {
        'cname': '',
        'pid': '',
        'keyword': '北京',
        'pageIndex': str(page),# 这里最好是字符串形式
        'pageSize': '10',
    }

    headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36'
}

    respose = requests.post(url=url,data=data,headers=headers)

    page_text = respose.json()
    # 打印餐厅信息 - 名字 地址
    for dic in page_text['Table1']:
        title = dic['storeName']
        addr = dic['addressDetail']

        print(title,addr)
    
    # 这只是第一页数据,如何拿到第二页、第三页数据........?
  • 爬取多页数据的代码
import requests

if __name__ == '__main__':
    # 爬取多页
    url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'

    # 拿到北京八页数据
    for page in range(1,9):
        data = {
            'cname': '',
            'pid': '',
            'keyword': '北京',
            'pageIndex': str(page),# 这里最好是字符串形式
            'pageSize': '10',
        }

        headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36'
    }

        respose = requests.post(url=url,data=data,headers=headers)

        page_text = respose.json()
        # 打印餐厅信息 - 名字 地址
        for dic in page_text['Table1']:
            title = dic['storeName']
            addr = dic['addressDetail']

            print(title,addr)

在这里插入图片描述

2.6 爬取国家药品监督总局中基于中华人民共和国化妆品生产许可证相关数据⭐⭐⭐

化妆品生产许可信息管理系统服务平台 - NMPA

在这里插入图片描述

  • 代码测试验证

用如下代码发起请求:

import  requests

if __name__ == "__main__":
    url = ' http://scxk.nmpa.gov.cn:81/xk/'
    
    headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36'
    }

    page_text = requests.get(url=url, headers=headers).text

    with open('./huazhuangpin.html','w',encoding='utf8') as fp:
        fp.write(page_text)

在这里插入图片描述在这里插入图片描述

结论:页面中的数据一定不是http://scxk.nmpa.gov.cn:81/xk/这个url请求到的,是别的请求方式请求到的

  • (很有可能是AJAX请求)
  • 抓包工具请求验证
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

利用在线JSON解析工具发现:

  • 首页对应的企业信息数据是通过ajax请求得到的

如下图,通过点击首页的公司发现

  • url的域名都是一样的,只有携带的参数(id)不一样
  • id值可以从首页对应的ajax请求到的json串中获取
  • 域名和id值拼接出一个完整的企业对应的详情页的url

在这里插入图片描述
在这里插入图片描述

<-------------------------------------------手动分割----------------------------------------------->

那上图获得的公司对应的化妆品生产许可证信息页面数据也是AJAX请求到的吗?
我们需要做相关验证:

  • 代码验证(笨方法)
  • 抓包工具验证
  • 抓包工具验证
    在这里插入图片描述

结论:我们不可能是通过对公司的化妆品生产许可证信息页面数据的url发请求获得数据的(看图)

  • 详情页数据信息也是动态加载出来的
    在这里插入图片描述
  • 分析详细数据的由来
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

json解析如下 :与详情页数据一致

{
	"businessLicenseNumber": "91320213355032183D",
	"businessPerson": "邱国忠",
	"certStr": "一般液态单元(护肤水类);膏霜乳液单元(护肤清洁类)",
	"cityCode": "",
	"countyCode": "",
	"creatUser": "",
	"createTime": "",
	"endTime": "",
	"epsAddress": "无锡市北塘区金山四支路11-1-12号",
	"epsName": "无锡邦士立生物科技有限公司",
	"epsProductAddress": "无锡市北塘区金山四支路11-1-12号",
	"id": "",
	"isimport": "N",
	"legalPerson": "邱国忠",
	"offDate": "",
	"offReason": "",
	"parentid": "",
	"preid": "",
	"processid": "202102240853582029gbgi",
	"productSn": "苏妆20160013",
	"provinceCode": "",
	"qfDate": "",
	"qfManagerName": "江苏省药品监督管理局",
	"qualityPerson": "宗同祥",
	"rcManagerDepartName": "江苏省药品监督管理局(无锡检查分局)",
	"rcManagerUser": "王丹、冯佳超",
	"startTime": "",
	"warehouseAddress": "",
	"xkCompleteDate": null,
	"xkDate": "2026-04-20",
	"xkDateStr": "2021-04-20",
	"xkName": "张贤",
	"xkProject": "",
	"xkRemark": "",
	"xkType": "202"
}

对不同的公司进行上述操作发现:

  • 所有的post请求的url都是一样的,只有参数id值是不同的。
  • 如果我们可以批量获取多家企业的id后,就可以将id和url形成一个完整的详情页对应详情数据的ajax请求的url
  • 爬取第一页详情数据并存储
import  requests
import json

if __name__ == "__main__":
    # 批量获取企业id值
    url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsList'
    # 参数的封装
    data = {
        'on': 'true',
        'page': '1',# 页码
        'pageSize': '15',# 每页显示的数据
        'productName': '',
        'conditionType': '1',
        'applyname': '',
        'applysn':'',
    }
    headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36'
    }

    id_list = [] # 存储企业的id
    all_data_list = [] # 存储所有企业的详情数据

    # 字典类型
    json_ids = requests.post(url=url, headers=headers,data=data).json()
    for dic in json_ids['list']:
        id_list.append(dic['ID'])
    # print(len(id_list))   # 15

    # 获取企业详情数据
    post_url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById'

    for id in id_list:
        data_id ={
            'id':id
        }
        # 发起请求
        detail_json = requests.post(url=post_url, data=data_id,headers=headers).json()
        # print(detail_json,'---------------ending------------')
        
        # 存储到列表
        all_data_list.append(detail_json)
    # 持久化存储
    fp = open('./allCompanyData.json','w',encoding='utf-8')
    json.dump(all_data_list,fp,ensure_ascii=False)
    print('over!!!')
  • 爬取前五页详情数据并存储
import  requests
import json

if __name__ == "__main__":
    # 批量获取企业id值
    url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsList'
    
    headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36'
    }

    id_list = [] # 存储企业的id
    all_data_list = [] # 存储所有企业的详情数据
    for page in range(1,6):
        # 参数的封装
        data = {
            'on': 'true',
            'page': str(page),# 页码
            'pageSize': '15',# 每页显示的数据
            'productName': '',
            'conditionType': '1',
            'applyname': '',
            'applysn':'',
        }


        # 字典类型
        json_ids = requests.post(url=url, headers=headers,data=data).json()
        for dic in json_ids['list']:
            id_list.append(dic['ID'])
        # print(len(id_list))   # 15

    # 获取企业详情数据
    post_url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById'
    for id in id_list:
        data_id ={
            'id':id
        }
        # 发起请求
        detail_json = requests.post(url=post_url, data=data_id,headers=headers).json()
        # print(detail_json,'---------------ending------------')
        
        # 存储到列表
        all_data_list.append(detail_json)
    print(len(all_data_list))
    # 持久化存储
    fp = open('./allCompanyData.json','w',encoding='utf-8')
    json.dump(all_data_list,fp,ensure_ascii=False)
    print('over!!!')

①json.dump()

交换参数不影响函数的使用

下节内容:数据解析

  • xpath

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK