当前位置:   article > 正文

爬虫实战(自用)requests模块、聚焦爬虫(数据解析)、selenium模块_使用requests库,让用户输入想要搜索的内容,使用get函数爬取搜狗网模拟用户输入并

使用requests库,让用户输入想要搜索的内容,使用get函数爬取搜狗网模拟用户输入并

一、requests模块

一、爬取搜狗首页的页面数据

import requests
# 指定url
# 发起请求,get方法会返回一个响应对象
res=requests.get(r'https://www.sogou.com/')
# 获取响应数据,text返回字符串类型的响应数据
str=res.text
print(str)
# 持久化存储
with open('./sogou.html','w',encoding='utf-8') as fp:
    fp.write(str)
print('爬取结束')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

结果:
在这里插入图片描述

二、爬取搜狗指定词条对应的搜索结果页面(简易网页采集器)

在这里插入图片描述
网址中有很多字母数字,我们只选择出有用的部分:
在这里插入图片描述
这么处理以后,页面还是一样的!
在这里插入图片描述
粘贴到Pycharm中会自动编码。(使用中文也没问题)

UA检测与UA伪装

UA:User-Agent(请求载体的身份标识)
我们使用requess.get去请求网页就不再是以浏览器的身份去访问,而是以爬虫程序去访问,门户网站的服务器会检测对应请求的载体身份标识,如果检测到为某一款浏览器,这个请求会被当作正常用户请求。

但是,如果检测到不是基于浏览器访问,则被视为不正常请求!(爬虫),则服务器很有可能拒绝该请求!

查询User-Agent:
在这里插入图片描述

所以我们一定要进行UA伪装!!! 伪装成某一款浏览器。

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/89.0.4389.82 Safari/537.36'
    }
    url='https://www.sogou.com/web'
    # 处理url携带的参数:封装到字典中(因为要动态收集)
    kw=input('enter a word:')
    param={
        'query':kw
    }
    # 对指定的url发起的请求对应的url是携带参数的,并且请求过程中处理了参数
    # headers代表头信息(用于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,'保存成功!!!')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在这里插入图片描述

三、破解百度翻译

比较翻译前后的url:

https://fanyi.baidu.com/?aldtype=16047#auto/zh/

# 翻译dog
https://fanyi.baidu.com/?aldtype=16047#en/zh/dog

# 翻译狗
https://fanyi.baidu.com/?aldtype=16047#zh/en/%E7%8B%97(这里也可以写成狗)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

它实际上是在你输入内容后进行局部页面刷新(不用你自己刷新)从而实现翻译。

通过使用谷歌自带抓包工具,进行抓包,没输入一个字符就观察一次,因为它涉及到局部页面刷新,属于ajax请求,所以要在Network中选择XHR进行查看。
在这里插入图片描述
在这里插入图片描述
最后发现,是第三个sug中包含了我们输入的参数dog,所以我们只需要这个内容中的URL地址。
在这里插入图片描述
并且可以看到,返回的数据为json串。(就是我们想要的数据)
在这里插入图片描述

从Content-Type可以看出响应数据的类型!

在这里插入图片描述

Post和Get的区别(使用不同函数)

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

在这里插入图片描述
data和params一样都用来处理参数。
在这里插入图片描述
上面的kw:dog就代表它的参数

实际上就是post是要携带用户信息的请求方式,get则是根据URL直接获取网页信息(即某个网址所包含的信息)。

post要获取的内容只靠网址是不能获取到的,需要提交一些额外的信息,这种信息在不同的网页中发挥不同功能。 例如在查询天气的网页,可能就是要输入城市信息;在登录某些网页时,又是账号和密码的载体。从这些可以看出get方法获取到的内容是稳定的(即每个人打开某个网页获得的信息相同),但是使用post需要输入特定信息,那么得到的网页内容就会有特异性。

post每次获取某个特定网页都需要输入额外信息,但get则直接输入URL即可(),这样也能看出post方法更加安全,因为额外信息不会直接暴露在网址上。

(百度翻译是post,因为需要我们向它传递dog这个数据,它才会返回值)

import requests
import json
if __name__=="__main__":
    # 1、指定url
    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/89.0.4389.82 Safari/537.36'
    }
    # 3、post请求参数处理(同get请求一致)
    data={
        'kw':'dog'
    }
    # 4、请求发送
    response=requests.post(url=post_url,data=data,headers=headers)
    # 5、获取响应数据(返回的是json)使用.json()返回的是对象
    # 如果确认服务器响应数据是json类型的,才可以使用.json()
    dic_obj=response.json()
    # print(dic_obj)

    # 6、持久化存储
    fp=open('./dog.json','w',encoding='utf-8')
    # 使用json.dump存储json文件,因为结果有中文,中文不支持ascii码,所以要设置为False
    json.dump(dic_obj,fp=fp,ensure_ascii=False)

    print('Over!!!')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在这里插入图片描述
使用[‘data’]即可获取data部分的list,进而使用它的相关数据。

在翻译dog的基础上,我们同样可以将dog设置成一个参数,通过我们传入的参数不同以达到获取不同单词的翻译结果。

动态化获取:

import requests
import json
if __name__=="__main__":
    # 1、指定url
    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/89.0.4389.82 Safari/537.36'
    }
    # 3、post请求参数处理(同get请求一致)
    word=input('enter a word:')
    data={
        'kw':word
    }
    # 4、请求发送
    response=requests.post(url=post_url,data=data,headers=headers)
    # 5、获取响应数据(返回的是json)使用.json()返回的是对象
    # 如果确认服务器响应数据是json类型的,才可以使用.json()
    dic_obj=response.json()
    # print(dic_obj)

    # 6、持久化存储
    filename='./'+word+'.json'
    fp=open(filename,'w',encoding='utf-8')
    # 使用json.dump存储json文件,因为结果有中文,中文不支持ascii码,所以要设置为False
    json.dump(dic_obj,fp=fp,ensure_ascii=False)

    print('Over!!!')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

在这里插入图片描述

四、爬取豆瓣电影分类排行榜

进入这个网址:豆瓣

当滑动滚轮时,滑到底部的时候页面会进行刷新使得右边的滑块又跑到了中央,所以我们可以利用这次刷新进行数据收集。

经过验证,确实是产生了ajax请求,和上面百度翻译类似。
在这里插入图片描述
在这里插入图片描述
下面是携带的五个参数。
在这里插入图片描述
意思就是说:我们让这个url发送get请求,并携带参数,就可以获取到响应的json文件,再进行持续化存储。

在这里插入图片描述
从?后开始到最后就是传递的参数,我们使用字典存储,也方便之后动态化。

我们也可以通过下图来获取具体的参数,直接复制到字典中存储即可。

在这里插入图片描述
根据每次滑动的变化,我们可以对每个参数值的含义进行猜测:(见代码)
在这里插入图片描述

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/89.0.4389.82 Safari/537.36'
    }
    # 属于get请求
    response=requests.get(url=url,params=param,headers=headers)

    list_data=response.json()

    fp=open('./douban.json','w',encoding='utf-8')
    json.dump(list_data,fp=fp,ensure_ascii=False)

    print('Over!!!')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这里插入图片描述
第一部电影确实是憨豆先生,实现了爬取。

(之后就是进一步的数据处理)

五、爬取肯德基餐厅查询

进入网址:http://www.kfc.com.cn/kfccda/storelist/index.aspx
在这里插入图片描述
在这里插入图片描述
发现,这又是一个局部网页刷新,所以和之前豆瓣一样,通过比对输入关键字前后抓包发生的变化,从而实现爬取。

import requests
if __name__=="__main__":
    post_url='http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
    data={
        'cname':'',
        'pid':'',
        'keyword': '四川',
        'pageIndex': '1',
        'pageSize': '10',
    }
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'
    }
    response=requests.post(url=post_url,data=data,headers=headers)
    # 返回对象是text类型,编码为utf-8
    fp=open('./KFC.txt','w',encoding='utf-8')
    fp.write(response.text)

    print('Over!!!')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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

六、爬取国家药品监督管理总局中基于中华人民共和国化妆品生产许可证相关数据(综合实战)

动态加载

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/89.0.4389.82 Safari/537.36'
    }
    response=requests.get(url=url,headers=headers)
    print(response.text)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

验证后发现,它并不是直接通过html实现数据的显示,可能是ajax实现,再进行验证。

也可以直接抓包,看对应的url是否有需要的数据:
在这里插入图片描述
在这里插入图片描述
这些由其它请求产生的数据,我们可以叫他们是动态加载出来的数据!

进行ajax抓包验证:
在这里插入图片描述
在这里插入图片描述
可以发现,首页的数据是由ajax提供的!

但我们需要的是每一家企业的详情页中的所有信息,该如何处理呢?

在这里插入图片描述
我们发现,每一行公司数据中都包含着一个ID数据,我们点开其中一个,进入详情页:
在这里插入图片描述
发现,该详情页的url是通过id来进行访问的,意思是每个id都对应了一个唯一的详情页面,我们可以先获取它的id,再以它的id为参数,进行详情页面的请求,即可实现详细信息的爬取。

我们对详情页进行抓包,又发现:
在这里插入图片描述
这个网页又是ajax刷新出来的动态网页,所以又可以通过之前的处理办法,提取其中的json文件:
在这里插入图片描述
同时也发现了它的参数(id)如下:
在这里插入图片描述

域名和id值进行拼接,拼接出一个完整的企业对应的详情页url。

注意:如果是post型,一定要记得传入参数!否则什么都得不到,因为post需要你向服务器提供数据,它才会返回相关的数据给你!

我们先对具体的详情页面进行试验,发现可以进行爬取:

import requests
import json
if __name__=="__main__":
    url='http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'
    }
    data={
        'id': 'ed59438f34ae47e794f4c7ee5137c1f7',
    }
    response=requests.post(url=url,data=data,headers=headers)
    list_data=response.json()

    fp=open('./药监局.json','w',encoding='utf-8')
    json.dump(list_data,fp=fp,ensure_ascii=False)

    print('Over!!!')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

接下来的任务就是将首页中获取的id与详情页面的url联系在一起,从而实现详情页的爬取:

import requests
import pandas as pd
import json
if __name__=="__main__":
    # 1、批量获取不同企业的id值
    url='http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsList'
    # 首页的请求为post,返回值为json
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'
    }
    # 传入post所需参数
    data={
        'on': 'true',
        'page': '1',    #代表第几页
        'pageSize': '15',
        'productName':'',
        'conditionType': '1',
        'applyname':'',
        'applysn':'',
    }
    response=requests.post(url=url,data=data,headers=headers)
    list_data=response.json()['list']
    list_id=[]
    for i in list_data:
        # 存入相关的id(共15个)
        list_id.append(i['ID'])
        # print(i)
    # print(list_id)
    # ['ed59438f34ae47e794f4c7ee5137c1f7', 'd5046c860bbb4e5198fa0dd99382b262', '8bc468fcdb83488681c616d2f7c59149',
    #  '5e45595403cc4509a266666a8a513c46', '246c9e4e2ad64e3f9518908e97a826f7', '76ec5f5a9048457986029282d0f99551',
    #  '670daa3bed864e029c4a17479314240b', '6aab6520cc164b9c9a86d3b5a371152e', 'e8d9c8e820f64c9b8b4c913bafdffecc',
    #  'f546d7d0b7a34944814291e2c0808500', 'aa42d5a6f10349b98f2fea44867a792c', '7b11ca443c804922815a9410e1fc6c3a',
    #  '72cf694b44a34627b27f6174332b69b1', '47cad475ffb6445da68a8eb83d89fd5f', '165b8a8d86314d5096ebe4e97ca0dd31']

    # 2、获取企业详情数据
    post_url='http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById'
    # 同样也是post型,需要传入具体的参数
    final_data=[]
    for i in list_id:
        # 遍历之前我们获取到的每一个id,进行每一个数据的读取
        post_data = {
            'id': i
        }
        post_response = requests.post(url=post_url, data=post_data, headers=headers)
        final_data.append(post_response.json())
    final_data=pd.DataFrame(final_data)
    # 将数据存入csv表格中
    # csv表格的编码为gbk,pycharm自带的编码是utf-8
    final_data.to_csv('药监局.csv',encoding='gbk')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

在这里插入图片描述
进一步,对所有页码进行遍历:(就是多了个循环,用于对页码进行遍历)

import requests
import pandas as pd
if __name__=="__main__":
	# 用于存储所有获取到的数据
    final_data = []
    # 1、批量获取不同企业的id值
    url='http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsList'
    post_url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById'
    # 首页的请求为post,返回值为json
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'
    }
    # 传入post所需参数
    for page in range(1,6): #先只要前五页
        page=str(page)
        data={
            'on': 'true',
            'page': page,    #代表第几页
            'pageSize': '15',   #代表一页有15个id
            'productName':'',
            'conditionType': '1',
            'applyname':'',
            'applysn':'',
        }
        response=requests.post(url=url,data=data,headers=headers)
        list_data=response.json()['list']
        list_id=[]
        for i in list_data:
            # 存入相关的id(共15个)
            list_id.append(i['ID'])
            # print(i)

        # 2、获取企业详情数据
        # 同样也是post型,需要传入具体的参数
        for i in list_id:
            # 遍历之前我们获取到的每一个id,进行每一个数据的读取
            post_data = {
                'id': i
            }
            post_response = requests.post(url=post_url, data=post_data, headers=headers)
            final_data.append(post_response.json())
    final_data=pd.DataFrame(final_data)
    # 将数据存入csv表格中
    # csv表格的编码为gbk,pycharm自带的编码是utf-8
    final_data.to_csv('药监局ALL.csv',encoding='gbk')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

二、聚焦爬虫(数据解析)

数据解析原理:使用数据解析,是因为有一些数据存在于标签之间或者在标签对应的属性值中。我们需要定位到具体标签的位置,或是标签相应的属性的位置,再获取标签中相关的数据。

大致有三类:
1、正则(适用于多种语言)
2、bs4(仅适用于Python)
3、xpath(重要)

编码流程变为:
1、指定url
2、发起请求
3、获取相应数据
4、数据解析
5、持久化存储

一、正则解析(爬取糗事百科中糗图中所有的图片)

在这里插入图片描述
从网站中可以看到:
在这里插入图片描述
图片是存储在具体的一个网页中的。
在这里插入图片描述

import requests
if __name__=='__main__':
    #如何爬取图片
    url='http://pic.qiushibaike.com/system/pictures/12413/124132664/medium/LBBZ8DUMBG0M6JEZ.jpg'
    #content返回的是二进制形式的图片数据
    # text(字符串) content(二进制) json()(对象)
    img_data=requests.get(url=url).content
    with open('./qiutu.jpg','wb') as fp:
        fp.write(img_data)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

步骤如下:先获取一整个页面,再对这个页面进行解析,获取其中的图片。

在这里插入图片描述
进行滑动后发现,它并不会像豆瓣一样动态更新,而是直接一页显示完,我们可以通过遍历page来获取所有图片。

在这里插入图片描述
可以发现,红框标签中包含了这一页的所有糗图。

进一步发现,在每一个糗图子类中的thumb标签下,存储了糗图(只有糗图,没有其他文字):
在这里插入图片描述
img src中存放的就是图片的地址(.jpg):
在这里插入图片描述

import requests
import re
if __name__=="__main__":
    url='https://www.qiushibaike.com/imgrank/'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'
    }
    # 使用通用爬虫对url对应的一整张页面进行爬取
    response=requests.get(url=url,headers=headers)
    # 获取源码数据
    page_text=response.text

    # 使用聚焦爬虫将页面中所有具体图片进行聚焦爬虫
    # 我们需要获取所有图片对应的src值,再对每个src值单独发送请求,得到每一张图片
    # < div class ="thumb" >
    #
    # < a href = "/article/124132664" target = "_blank" >
    # < img src = "//pic.qiushibaike.com/system/pictures/12413/124132664/medium/LBBZ8DUMBG0M6JEZ.jpg" alt = "糗事#124132664" class ="illustration" width="100%" height="auto" >
    # < / a >
    #
    # < / div >
    ex='<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
    img_src_list=re.findall(ex,page_text,re.S)
    print(img_src_list)
    # 发现存下来的地址缺少协议头:https:
    # '//pic.qiushibaike.com/system/pictures/12412/124120243/medium/BOKRF0W5573YHP7J.jpg'
    # 在添加协议头后,再使用get即可获取图片
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

二、bs4数据解析

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

soup提供的用于数据解析的函数

1、soup.tagName(自己输入)

在这里插入图片描述
这里的html head body div都是tagName(标签名)
在这里插入图片描述
它只返回第一次出现的tagName对应的标签,不能返回多个。

2、soup.find()

1)soup.find(‘div’)等同于soup.div

2)属性定位(根据具体属性定位到对应属性的标签)
soup.find(‘div’,class_/id/attr=‘song’)(这里class要加下划线,不然会被当作关键字)

3、soup.find_all()

find_all会返回符合要求的所有标签,用法同soup.find()

4、soup.select()

需要传入某种选择器(id、类、标签选择器),返回是一个列表

class选择器:.类名
标签选择器:直接写标签名
id选择器:#Id

层级选择器:

(大于号表示一个层级,也可以将大于号替换为空格,代表之间有多个层级)

soup.select(’.tang > ul > li > a’):查找.tang类下的ul标签下的li标签下的a标签

    print(soup.select('div .thumb > a > img'))
  • 1

选择div标签中类名为thumb的类下面的标签为a的下面的标签为img的内容。
在这里插入图片描述

[<img alt="糗事#124138955" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124138955/medium/G7V66LF8S6TGOU6G.jpg" width="100%"/>, <img alt="糗事#124136388" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124136388/medium/48MW1SMPCL45S4Z4.jpg" width="100%"/>, <img alt="糗事#124123833" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12412/124123833/medium/PGFQADGTCL8T0EMD.jpg" width="100%"/>, <img alt="糗事#124130144" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124130144/medium/0RUTLVJ9L534RDCG.jpg" width="100%"/>, <img alt="糗事#124129027" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12412/124129027/medium/MZ936V0QCZBA0DIX.jpg" width="100%"/>, <img alt="糗事#124015279" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12401/124015279/medium/B8ROANAYSIWZQ07X.jpg" width="100%"/>, <img alt="糗事#124039381" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12403/124039381/medium/N6P3FHIGAV0N4Q1U.jpg" width="100%"/>, <img alt="糗事#124132227" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124132227/medium/C4MRAF8159IZEAD9.jpg" width="100%"/>, <img alt="糗事#124131947" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124131947/medium/ES1BAH06YM3O2AC7.jpg" width="100%"/>, <img alt="糗事#124137047" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124137047/medium/FZIWPL2PFOFYQMRQ.jpg" width="100%"/>, <img alt="糗事#124138959" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124138959/medium/EULVRT9M3ZZFDQOQ.jpg" width="100%"/>, <img alt="糗事#124139238" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124139238/medium/JY5AT3YY3JTA4SSY.jpg" width="100%"/>, <img alt="糗事#124128456" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12412/124128456/medium/INCK9584YU11CLCO.jpg" width="100%"/>, <img alt="糗事#124134443" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124134443/medium/4WYYQG8Z3VD7AQ9Z.jpg" width="100%"/>, <img alt="糗事#124131716" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124131716/medium/LTK72H5NS7X3KO0R.jpg" width="100%"/>, <img alt="糗事#123999393" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12399/123999393/medium/EWBBQAMBHDBE3H4G.jpg" width="100%"/>, <img alt="糗事#124135221" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124135221/medium/0R2D84TTU3GHBOJG.jpg" width="100%"/>, <img alt="糗事#124131622" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124131622/medium/BJS1EAY8DK0M2Q59.jpg" width="100%"/>, <img alt="糗事#124130884" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124130884/medium/TZF8FMUCXDKKZWM3.jpg" width="100%"/>, <img alt="糗事#124135578" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124135578/medium/9S28RZ4PIP610QQ5.jpg" width="100%"/>, <img alt="糗事#124136384" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124136384/medium/YHEGWI2C4DVYR7BV.jpg" width="100%"/>, <img alt="糗事#124134929" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124134929/medium/JP7Q2UQ4XTG8ZPGF.jpg" width="100%"/>, <img alt="糗事#124129563" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12412/124129563/medium/FQAINA29JKXU181G.jpg" width="100%"/>, <img alt="糗事#124139821" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12413/124139821/medium/V41ONJ5MYOZRHABV.jpg" width="100%"/>, <img alt="糗事#124123264" class="illustration" height="auto" src="//pic.qiushibaike.com/system/pictures/12412/124123264/medium/AHAVUX4WW70CAMRI.jpg" width="100%"/>]
  • 1

获取标签中的文本数据

之前是定位到具体的标签,现在是利用定位到的具体标签来提取其中的数据。

soup.a.text/string/get_text(),用于读取文本数据

text/get_text():可以获取一个标签中的所有文本内容

string:只可以获取该标签下面直系的文本内容

我们上面想要的src不属于文本数据!

获取标签中属性值

直接使用 [ 属性名 ]

print(soup.select('div .thumb  a  img')[0]['src'])
  • 1

我们成功从中提取到了src!!!

//pic.qiushibaike.com/system/pictures/12405/124058306/medium/X8FX01T2TYWYF66L.jpg
  • 1

三、bs4实战:爬取三国演义小说所有的章节标题和章节内容

在这里插入图片描述
在这里插入图片描述
这个跟爬取药监局的例子相似,需要现在主页面获取到每一个子页面的url,再对每一个子页面进行访问,读取子页面中的文本内容。

在这里插入图片描述
这个网站并不是动态加载(ajax),而是将具体网址写入标签属性中,所以需要用到数据解析!(药监局那个是动态加载)

import requests
from bs4 import BeautifulSoup
if __name__=="__main__":
    # 对首页页面数据进行爬取
    url='https://www.shicimingju.com/book/sanguoyanyi.html'
    # 进行UA伪装
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'
    }
    page_text=requests.get(url=url,headers=headers).text

    # 在首页中解析出章节的标题和详情页的url
    # 1、实例化Beautiful Soup对象,将页面源码加载到该对象中
    soup=BeautifulSoup(page_text,'lxml')
    # print(soup.select('.book-mulu li a'))
    book_list=soup.select('.book-mulu li a')
    book_url=[]
    # https://www.shicimingju.com/book/sanguoyanyi/1.html
    # 对比原网址,添加https://www.shicimingju.com
    head='https://www.shicimingju.com'
    for i in book_list:
        temp_str=head+i['href']
        book_url.append(temp_str)
    # print(book_url)
    # 'https://www.shicimingju.com/book/sanguoyanyi/1.html'

    # 将书中内容存入字典
    books={}
    fp=open('./sanguo.txt','w',encoding='utf-8')
    for url in book_url:
        page_text=requests.get(url=url,headers=headers).text
        soup=BeautifulSoup(page_text,'lxml')
        div_tag=soup.find('div',class_='chapter_content')
        content=div_tag.text
        print(content)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

四、xpath解析

最常用且最便捷高效的一种新方法,通用性。

xpath解析原理:

1、实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中

2、调用etree对象中的xpath方法,结合着xpath表达式实现标签的定位和内容的捕获

如何实例化一个etree对象:from lxml import etree

1、将本地html文档重点源码数据加载到etree对象中:
etree.parse(filePath)

2、可以将从互联网上获取的源码加载到该对象中:
etree.HTML(‘page_text’)

xpath(‘xpath表达式’),返回一个列表!

    response=requests.get(url=url,headers=headers).text
    tree=etree.HTML(response)
    r=tree.xpath('/html/head/title')
    r=tree.xpath('/html//div')
    r=tree.xpath('//div')
  • 1
  • 2
  • 3
  • 4
  • 5

/ 表示从根节点开始,一个 / 表示一个层级,而//表示多个层级,或者表示可以从任意位置开始定位。(所有)

属性定位:

tagName[@attrName=“attrValue”]

    r=tree.xpath('//div[@class="song"]')
  • 1

索引定位:

    r=tree.xpath('//div[@class="song"]/p')
  • 1

表示div标签下,类名为song下的p标签,可以在后面使用 [1] 索引,从1开始!!!

取文本:

    r=tree.xpath('//div[@class="song"]/ul/li[1]/a/text()')
    # 返回结果为列表
  • 1
  • 2

取得,a标签下的文本内容。
/text(),获取的是标签中直系的文本内容

//text(),获取的是标签中非直系(所有的)文本内容

取属性:

    r=tree.xpath('//div[@class="song"]/img/@src')
    # 返回结果为列表
  • 1
  • 2

/@属性名 (/@src,获取img标签下的src属性)

五、xpath解析实战:58二手房

三、selenium模块的基本使用

一、引入

回顾一下,我们是怎么判断网页中的数据是否为动态加载:

打开抓包工具,在当前网页的url对应内容中进行搜索,看是否有相应的内容:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
搜索不到,显然就是动态加载的!

那如何快速,准确的找到需要的数据在哪里呢?
在这里插入图片描述
在红框中按下 ctrl + f 输入你需要查询的信息,进行搜索。

可以发现,如果使用像上面的方法进行查找的话,会比较耗时,我们就需要使用selenium模块!

二、selenium模块

1、作用

1、它能帮助便捷的获取网站中动态加载的数据!
2、便捷地使用模拟登陆!

selenium是基于浏览器自动化的一个模块。(就是自动地使用浏览器的相关功能,让他自己去操纵浏览器,不用我们自己去弄)

2、使用流程

环境安装:pip install selenium
下载一个浏览器的驱动程序:
http://npm.taobao.org/mirrors/chromedriver/
在这里插入图片描述

驱动程序和版本要对应。对照表

再把驱动放在你项目的文件夹中。

在这里插入图片描述
实例化一个浏览器对象(传入浏览器的驱动程序)

from selenium import webdriver
# 实例化一个浏览器对象(传入浏览器的驱动程序)
bro=webdriver.Chrome(executable_path='./chromedriver.exe')
  • 1
  • 2
  • 3

用代码操纵你的浏览器!

以药监局的例子为例:

1、先操纵浏览器打开药监局的网站:

from selenium import webdriver
# 实例化一个浏览器对象(传入浏览器的驱动程序)
bro=webdriver.Chrome(executable_path='./chromedriver.exe')
# 对指定网页发送请求
bro.get('http://scxk.nmpa.gov.cn:81/xk/')
  • 1
  • 2
  • 3
  • 4
  • 5

2、获取浏览器当前页面的页面源码数据(公司名字)

from selenium import webdriver
from lxml import etree
from time import sleep
# 实例化一个浏览器对象(传入浏览器的驱动程序)
bro=webdriver.Chrome(executable_path='./chromedriver.exe')
# 对指定网页发送请求
bro.get('http://scxk.nmpa.gov.cn:81/xk/')
# 获取浏览器当前页面的源码数据
page_text=bro.page_source

# 解析企业名称(以xpath为例)
tree=etree.HTML(page_text)
li_list=tree.xpath('//ul[@id="gzlist"]/li')
for li in li_list:
    name=li.xpath('./dl/@title')[0]
    print(name)
# 关闭浏览器
sleep(5)    #暂停五秒后关闭
bro.quit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

3、其他自动化操作(以淘宝搜索为例)

我们要先找到搜索框在哪里?
在这里插入图片描述
打开检查,找到搜索框对应的源码,发现里面有一个input标签,id=‘q’。

标签定位:
在这里插入图片描述

search_input=bro.find_element_by_id('q')
  • 1

如何向搜索框中传值呢?

search_input=bro.find_element_by_id('q')
# 标签交互(传入想输入搜索框的东西)
search_input.send_keys('Iphone')
  • 1
  • 2
  • 3

我们还需要点击搜索按钮,我们再去找搜索按钮对应的源码:
在这里插入图片描述
在这里插入图片描述
它有两个标签名,用哪一个都行但不能一起用!

from selenium import webdriver
from time import sleep
bro=webdriver.Chrome(executable_path='./chromedriver.exe')

bro.get('https://www.taobao.com/')

# 想要通过搜索框搜索数据
# 先要找到那个搜索框(标签定位)
search_input=bro.find_element_by_id('q')
# 标签交互(传入想搜索的东西)
search_input.send_keys('Iphone')

# 点击搜索按钮
btn=bro.find_element_by_css_selector('.btn-search')  #这里用class搜索也可以
sleep(3)
btn.click()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

因为没有登录,所以运行结果如下:
在这里插入图片描述

如何实现页面滚轮下滑效果呢?

进入网页检查中的console输入:
在这里插入图片描述
即可实现滚轮效果,现在需要使得程序知道怎么操作。

from selenium import webdriver
from time import sleep
bro=webdriver.Chrome(executable_path='./chromedriver.exe')

# 发起请求
bro.get('https://www.taobao.com/')

# 想要通过搜索框搜索数据
# 先要找到那个搜索框(标签定位)
search_input=bro.find_element_by_id('q')
# 标签交互(传入想搜索的东西)
search_input.send_keys('Iphone')

# 实现滚轮下滑效果
# 需要执行一组js程序
bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(2)

# 点击搜索按钮
btn=bro.find_element_by_css_selector('.btn-search')  #这里用class搜索也可以

bro.get('https://www.baidu.com')
sleep(2)
# 回退(倒退)
bro.back()
sleep(2)
# 前进
bro.forward()
sleep(3)
btn.click()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

三、selenium处理iframe

什么是iframe???
用于实现网页的嵌套。

我们来看看如何拖动一个方块:
在这里插入图片描述

在这里插入图片描述
我们先找到需要被拖动方块的源码。
在这里插入图片描述
为什么会报错呢?
它说没有找到我们想要的标签,我们id也没有输错。
原因:
在这里插入图片描述
它是包含在一个叫做iframe的标签下,所以才导致程序无法找到。

如何定位的标签存在于iframe标签之中,直接寻找是寻找不到的!

实现在iframe下的定位:

from selenium import webdriver
from time import sleep

bro=webdriver.Chrome(executable_path='./chromedriver.exe')

bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
# 如何定位的标签存在于iframe标签之中,直接寻找是寻找不到的!
# 传入的参数是Id
bro.switch_to.frame('iframeResult') #切换浏览器标签定位的作用域(默认为最外面大的html标签)

div=bro.find_element_by_id('draggable')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

模拟人操作鼠标,进行滑块的拖动:

from selenium import webdriver
from time import sleep
# 导入动作链对应的类
from selenium.webdriver import ActionChains

bro=webdriver.Chrome(executable_path='./chromedriver.exe')

bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
# 如何定位的标签存在于iframe标签之中,直接寻找是寻找不到的!
# 传入的参数是Id
bro.switch_to.frame('iframeResult') #切换浏览器标签定位的作用域(默认为最外面大的html标签)
div=bro.find_element_by_id('draggable')
# 动作链
action=ActionChains(bro)
# 点击长按指定的标签
action.click_and_hold(div)

for i in range(5):
    # perform()立即执行动作链操作
    action.move_by_offset(17,0).perform()   #做移动偏移(x,y)传入水平、竖直方向偏移
    sleep(0.3)
# 释放工作链
action.reset_actions()

bro.quit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

在这里插入图片描述

四、selenium模拟登录(模拟登录QQ空间)

在这里插入图片描述
主要就是红框中的三个模块:账号、密码、登录按钮。

在这里插入图片描述
由于,默认情况下,是要我们进行扫码,我们还需要点击右下角账号密码登录。
在这里插入图片描述
在这里插入图片描述
注意!这里的账号密码登录还是在iframe标签下!!所以不能直接请求。

from selenium import webdriver
from time import sleep
bro=webdriver.Chrome(executable_path='../../chromedriver.exe')
bro.get('https://qzone.qq.com/')
# 参数为id
bro.switch_to.frame('login_frame')
a_tag=bro.find_element_by_id('switcher_plogin')
a_tag.click()   #定位到之后进行点击
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述
定位账号和密码:
在这里插入图片描述
在这里插入图片描述

from selenium import webdriver
from time import sleep
bro=webdriver.Chrome(executable_path='../../chromedriver.exe')
bro.get('https://qzone.qq.com/')
# 参数为id
bro.switch_to.frame('login_frame')
a_tag=bro.find_element_by_id('switcher_plogin')
a_tag.click()   #定位到之后进行点击

# 寻找用户名、密码输入框
userName_tag=bro.find_element_by_id('u')
passWord_tag=bro.find_element_by_id('p')

# 录入数据
userName_tag.send_keys('1229482340')
passWord_tag.send_keys('1111')

# 寻找工作按钮
btn=bro.find_element_by_id('login_button')
btn.click()

sleep(3)

bro.quit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

现在不能直接登录,需要进行滑块验证!

五、让浏览器不可视(无头浏览器)

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

# 无可视化参数
chrome_options=Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')

bro=webdriver.Chrome(executable_path='./chromedriver.exe',options=chrome_options)
bro.get('https://www.baidu.com')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

六、规避selenium被网站检测

from selenium import webdriver
# 实现无头浏览器
from selenium.webdriver.chrome.options import Options
# 实现规避检测
from selenium.webdriver import ChromeOptions

# 无可视化参数
chrome_options=Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')

# 如何让selenium规避被检测到的风险
option=ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])

bro=webdriver.Chrome(executable_path='./chromedriver.exe',chrome_options=chrome_options,options=option)
bro.get('https://www.baidu.com')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/352906
推荐阅读
  

闽ICP备14008679号