# 爬虫初始

### 1. python网络请求模块

* requests模块（主要）
* urllib模块

### 2. requests模块

* python中原生的一款基于网络请求的模块，功能强大，简单快捷，效率极高
* 作用：模拟浏览器发请求

#### 2.1 环境安装

* pip install requests
* ps：pycharm自带python环境，所以在电脑命令中安转可能在pycharm中导包不了，所以最好在pycharm的终端中进行安转

#### 2.2 如何使用

1. 指定url
2. 向指定url发起请求
   * get请求
   * post请求
3. 获取响应对象的数据值
4. 持久化存储

* 入门案例：

```
import requests
if __name__=='__main__':
    # 指定url
    url='https://www.sogou.com/'
    # 发起请求
    # get方法会返回一个响应对象
    response=requests.get(url=url)
    # 获取响应对象数据
    # 以字符串方式返回页面源码
    page_text=response.text
    print(page_text)
    # 持久化存储
    # 在当前文件夹存储
    with open('./sougou.html','w',encoding='utf-8') as fp:
        fp.write(page_text)
    print('爬取数据结束！！！！')
```

* ps:对于爬取的html数据没有换行，可以在pycharm中全选代码后按ctrl+alt+L快捷键换行

### 3. 搜狗结果页采集(网页采集器)

```
# UA检测：
# 门户网站的服务器会检测对应请求的载体身份标识，如果检测的请求的载体身份标识为某一浏览器
# 说明该请求为正常请求。但是，如果请求的载体身份标识不是基于某一款浏览器时，则标识该请求
# 是不正常的(爬虫)，则服务器就有可能会拒绝该次请求，所以要进行UA伪装
# UA伪装：让爬虫对应的请求载体身份标识伪装成某一浏览器
# UA：User-Agent
import requests
if __name__=='__main__':
    # UA伪装：将对应的User-Agent封装到一个字典中
    headers={
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36 Edg/97.0.1072.62'
    }
    url='https://www.sogou.com/web?'
    # 处理url携带的参数：封装到字典中,一个参数一个键值对
    # 动态设置参数
    kw=input('enter a word：')
    param={
        'query':kw
    }
    # 对指定的url发起的请求对应的url是携带参数的，并且请求过程中处理了参数
    # 第二个参数处理请求参数
    # 第三个参数UA伪装
    response=requests.get(url=url,params=param,headers=headers)
    page_text=response.text
    fileName=kw+'.html'
    with open(fileName,'w',encoding='utf-8') as fp:
        fp.write(page_text)
    print(fileName,'保存成功')
```

#### 3.1 UA检测与UA伪装

* UA检测：
* UA：User-Agent
* 门户网站的服务器会检测对应请求的载体身份标识，如 果检测的请求的载体身份标识为某一浏览器\
  说明该请求为正常请求。但是，如果请求的载体身份标识不是基于某一款浏览器时，则标识该请求\
  是不正常的(爬虫)，则服务器就有可能会拒绝该次请求，所以要进行UA伪装
* UA伪装：让爬虫对应的请求载体身份标识伪装成某一浏览器

#### 3.2 可变参数

* 在页面参数设置时，可以设置自己输入控制可变参数来爬取自己想要的页面，如上的搜狗搜索结果页面

### 4. 破解百度翻译

```
import requests
import json
if __name__=='__main__':
    post_url='https://fanyi.baidu.com/sug'
    head={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36 Edg/97.0.1072.62'
    }
    # post请求参数处理(同get一样)
    # 这里也能改成动态的参数
    data={
        'kw':'dog'
    }
    # 发送post请求
    response=page_text=requests.post(url=post_url,data=data,headers=head)
    # 服务器返回的是json数据
    # json()方法返回的是obj（如果确认服务器返回的是json类型，才能用）
    dic_obj = response.json()
    fp=open('./dog.json','w',encoding='utf-8')
    # 录入文件
    # 第三个参数为是否能用ASCII码进行编码
    json.dump(dic_obj,fp=fp,ensure_ascii=False)
    print('over!!')

```

#### 4.1 关于ajax请求与服务器返回类型

* ajax请求：即不刷新页面也能进行数据更新，ajax请求返回的就是json类型数据
* 关于服务器返回的类型以及post请求的url可以在浏览器的抓包工具的XHR分类中查看

#### 4.2 关于json格式

* 可以把抓取到的json语句在json在线解析中解析成标准格式以查看内容

### 5. 豆瓣电影爬取

* 跟破解百度翻译差不多

```
import json
import requests
if __name__=='__main__':
    url='https://movie.douban.com/j/chart/top_list?'
    par={
        '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/97.0.4692.71 Safari/537.36 Edg/97.0.1072.62'
    }
    response=requests.get(url=url,params=par,headers=headers)
    list_data=response.json()
    fp=open('./豆瓣电影.json','w',encoding='utf-8')
    json.dump(list_data,fp=fp,ensure_ascii=False)
    print('over!!!')
```

### 6. KFC餐厅查询爬取

```
import json
import requests
if __name__=='__main__':
    url='http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?'
    key=input('请输入城市：')
    par={
        'op':'keyword',
        'cname':'',
        'pid':'',
        'keyword': key,
        'pageIndex': '1',
        'pageSize': '100'
    }
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36 Edg/97.0.1072.62'
    }
    response=requests.post(url=url,params=par,headers=headers)
    page_text=response.text

    # 将字符串转换为json类型
    page_json=json.loads(page_text)
    fp=open('./kfc.json','w',encoding='utf-8')
    json.dump(page_json,fp=fp,ensure_ascii=False)
    print('over!!!')
```

* ps： 如果抓取的数据类型不是json类型，也可以用json.loads()方法把抓取的字符串转换为json数据类型

#### 6.1 关于多页数据的爬取

* 我们爬取页面时有时候会遇到多页面，想全部爬取数据怎么办呢？
* 如果是ajax请求页面一般会有类似于pageIndex和pageSize的参数，这个时候我们可以把pageSize参数的数据设置大一点就可以爬取所有页面的数据了，也可以在爬取的json文件动态获取总数据数进行爬取，或者用循环遍历所有的pageIndex获取

### 7. 综合练习-药监总局

```
import json
import requests
if __name__=='__main__':
    url='http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsList'
    data={
        'on': 'true',
        'page': '1',
        'pageSize': '',
        'productName':'',
        'conditionType': '1',
        'applyname':'',
        'applysn':''
    }
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36 Edg/97.0.1072.62'
    }
    json_ids=requests.post(url=url,headers=headers,data=data).json()
    id_list=[]#存储所有的企业id
    all_data_list=[]#存储所有的企业详情数据
    # 获取所有的ID
    for dic in json_ids['list']:
        id_list.append(dic['ID'])
    post_url='http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById'
    for id in id_list:
        data={
            'id':id
        }
        detail_json=requests.post(url=post_url,headers=headers,data=data).json()
        all_data_list.append(detail_json)
    fp=open('./药监总局.json','w',encoding='utf-8')
    json.dump(all_data_list,fp=fp,ensure_ascii=False)
    print('over!!!!')
```

#### 7.1 关于发送请求中data与params区别

* data:是添加到请求体中的，用于post请求
* params：是添加到url的请求字符串中的，用于get请求

### 8. requests库的text方法、content方法、json类型的区别

* text方法：返回字符串
* content方法：返回二进制
* json方法：返回对象

### 9. 关于post请求与get请求区别

* post请求：
  * post请求没有编码集的限制
  * post参数在REQUSET BODY中，用户不可见，相对安全
  * 参数长度无限制
  * post请求会先把请求头发送到服务器进确认，然后才真正发送数据
  * post请求不会对数据进行缓存
  * post请求一般用于修改和写入数据
* get请求：
  * get请求只能用ASCLL码
  * get请求参数在url中，用户可见
  * 浏览器会对url长度进行限制，所以get请求参数长度一般也会被限制，不同浏览器限制长度不一样
  * get请求会把请求头与数据一起发送
  * get请求会把数据进行缓存
  * get请求一般用于搜索排序和筛选之类的操作
