当前位置:   article > 正文

(7) 浅学 “爬虫” 过程 (概念+练习)_soup = beautifulsoup(fp,'lxml')

soup = beautifulsoup(fp,'lxml')

爬虫:请求网站并提取数据的自动化程序。 通过编写程序,模拟浏览器上网,然后让其去互联网上抓取数据的过程。

目录

爬虫的分类

Robots协议

常用请求头/响应头、http/s、加密方式

urllib 模块 (比较繁琐)

urllib.request.urlopen()基本使用

requests模块 (简单便捷,接下来都是使用的requests模块)

如何使用:

爬取搜狗首页 

Day1

requests巩固案例

破解百度翻译

Json

爬取豆瓣电影分类排行榜

Ajax(阿贾克斯)

Day2

数据解析

图片爬取

正则解析

bs4解析

如何实例化BeautifulSoup对象:

 提供的用于数据解析的方法和属性:

 获取标签之间的文本数据:

获取标签中属性值:

 bs4解析案例

xpath解析(便捷高效、通用)

如何实例化一个etree对象:

 xpath表达式:

 xpath解析案例之二手房源

xpath解析之图片解析

Day3

验证码识别

Day4

异步爬虫


 

爬虫的分类

根据使用场景,爬虫可以分为三类:

1.通用爬虫(大而全)

功能强大,采集面广泛,通常用于搜索引擎,比如百度浏览器就是一个很大的爬虫程序。

2.聚焦爬虫(小而精)

建立在通用爬虫的基础上,抓取页面中特定的局部内容,比如说去某个网站批量获取某些数据。

3.增量式爬虫(只采集更新后的内容)

这其实是聚焦爬虫的一个迭代爬虫,检测网站中数据更新情况,只会抓取网站中最新更新的数据。

Robots协议

爬虫中有一个Robots协议,又称为“网络爬虫排除标准”,君子协议,规定了网站中哪些数据可以被爬虫爬取,哪些不可被爬取。一般情况下直接在网站首页网址后面加/robots.txt就能查看,比如百度的Robots协议就在https://www.baidu.com/robots.txt 。

常用请求头/响应头、http/s、加密方式

http协议:就是服务器和客户端进行数据交互的一种形式

https协议:安全的超文本传输协议,采用证书密钥加密

常用请求头:User-Agent(请求载体的身份标识)

                       Connection(请求完毕后,是断开连接还是保持连接)

常用响应头:Content-Type(服务器响应回客户端的数据类型)

加密方式:1.对称密钥加密:客户端将要传输到服务器的参数加密,传输时携带密钥

                   2.非对称密钥加密:服务端创建密钥对,将公钥发给客户端,客户端使用密钥对消息加

                                                     密,将加密信息发给服务端,服务端再用私钥解密。

                    3.证书密钥加密:公开密钥-->证书认证机构-->给公钥签名(防伪)-->证书

urllib 模块 (比较繁琐)

urllib中包括了四个模块:urllib.request, urllib.error, urllib.parse, urllib.robotparser

urllib.request可以用来发送请求request和获取请求request的结果

urllib.error包含了urllib.request产生的异常

urllib.parse用来解析和处理URL

urllib.robotparse用来解析页面的robots.txt文件

urllib.request.urlopen()基本使用

urllib.request 模块提供了最基本的构造 HTTP 请求的方法,利用它可以模拟浏览器的一个请求发起过程,同时它还带有处理 authenticaton (授权验证), redirections (重定向), cookies (浏览器Cookies)以及其它内容。

  1. import urllib.request #导入模块
  2. reaponse=urllib.request.urlopen("URL") #获取网页内容
  3. html=reaponse.read() #读取网页内容,放到html
  4. print(html) #内容以b开头,打印出来是二进制的数据
  5. html2=html.decode('utf-8') #解码
  6. print(html2)

requests模块 (简单便捷,接下来都是使用的requests模块)

requests模块:python中原生的一款基于网络请求到模块,功能强大,简单便捷,效率极高

作用:模拟浏览器发请求

如何使用:

                   1.指定url  2.发起请求  3.获取响应数据  4.持久化存储

爬取搜狗首页 

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

Day1

requests巩固案例

User-Agent:请求载体的身份标识

UA伪装:如果门户网站的服务器会检测对于请求的载体身份标识,如果检测到请求的载体身份标识为某一款浏览器。

注:说明该请求是一个正常请求,但是如果检测到请求的载体身份标识不是基于某一款浏览器的,则表示该请求为不正常请求(爬虫),则服务器端很可能拒绝该次请求,所以在爬虫中进行UA伪装。

破解百度翻译

 post请求(携带了参数),响应数据是一组json数据

  1. import json
  2. import requests
  3. #1.指定url
  4. post_url='https://fanyi.baidu.com/sug'
  5. #2.进行UA伪装
  6. headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0'}
  7. #3.post请求参数处理(同get请求一致)
  8. word=input('输入一个单词:')
  9. data={'kw':word}
  10. #4.请求发送
  11. response=requests.post(url=post_url,data=data,headers=headers)
  12. #5.获取响应数据
  13. response.text #获取到字符串类型数据
  14. dic_obj=response.json() #json()方法返回的是一个字典的对象obj(如果确定响应数据是json类型,才可以使用json())
  15. #6.持久化存储
  16. filename=word+'.json'
  17. fp=open(filename,'w',encoding='utf-8')
  18. json.dump(dic_obj,fp=fp,ensure_ascii=False) #(对象,文件,中文)
  19. print('over!!!!!!!')

Json

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。易于人阅读和编写,可以在多种语言之间进行数据交换 [5]  。同时也易于机器解析和生成。

JSON是一个标记符的序列。这套标记符包含六个构造字符字符串数字和三个字面名

JSON是一个序列化的对象数组

json.dump() 是把python对象转换成json对象生成一个fp的文件流,和文件相关。ensure_ascii=True:默认输出ASCLL码,如果把这个该成False,就可以输出中文。

Json语法: JSON 语法是 JavaScript 对象表示语法的子集。

  • 数据在名称/值对中
  • 数据由逗号 , 分隔
  • 使用斜杆来转义 \ 字符
  • 大括号 {} 保存对象
  • 中括号 [] 保存数组,数组可以包含多个对象

Json对象:

JSON 对象在大括号 { } 中书写:

{key1 : value1, key2 : value2, ... keyN : valueN }

Json数组:

JSON 数组在中括号 [ ] 中书写:(数组可以包含多个对象)

[
    { key1 : value1-1 , key2:value1-2 }, 
    { key1 : value2-1 , key2:value2-2 }, 
    { key1 : value3-1 , key2:value3-2 }, 
    ...
    { key1 : valueN-1 , key2:valueN-2 }, 
]

JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。

var obj={a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹

var json='{"a": "Hello", "b": "World"}'//这是一个JSON字符串,本质是一个字符串

要实现从JSON字符串转换为JS对象,使用 JSON.parse() 方法:

var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //结果是 {a: 'Hello', b: 'World'}

要实现从JS对象转换为JSON字符串,使用 JSON.stringify() 方法:

var json = JSON.stringify({a: 'Hello', b: 'World'}); //结果是 '{"a": "Hello", "b": "World"}'' 

爬取豆瓣电影分类排行榜

 滑动滚轮,当滑到底部会加载一组新的电影数据,地址栏(url)没变是做的一个页面的局部刷新,是发起了Ajax(阿贾克斯)请求

  1. import json
  2. import requests
  3. url='https://movie.douban.com/j/chart/top_list'
  4. #将参数封装到字典
  5. param={
  6. 'type':'24',
  7. 'interval_id':'100:90',
  8. 'action':'',
  9. 'start':'0', #从库中第几部电影开始取
  10. 'limit':'20', #一次取多少部电影
  11. }
  12. headers={'User-Agent':
  13. 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0'}
  14. response=requests.get(url=url,params=param,headers=headers)
  15. list_data=response.json()
  16. fp=open('./douban.json','w',encoding='utf-8')
  17. json.dump(list_data,fp=fp,ensure_ascii=False)
  18. print('over!!!!!')

Ajax(阿贾克斯)

AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

AJAX 通过在后台与服务器进行少量数据交换,使网页实现异步更新。这意味着可以在不重载整个页面的情况下,对网页的某些部分进行更新。

 

Day2

数据解析

数据解析原理:解析的局部的内容都会在标签之间或者标签对应的属性中进行存储

                          1.进行指定标签的定位

                          2.标签或者标签对应的属性中存储的数据值进行提取(解析)

聚焦爬虫,是爬取页面中指定的页面内容。首先爬整张页面内容,再将指定内容提取出来,提取过程就叫数据解析。

编码流程:1.指定url

                   2.发起请求

                   3.获取响应数据

                   4.数据解析

                   5.持久化存储

数据解析分类:正则、bs4、xpath

图片爬取

  1. import requests
  2. url='https://wx1.sinaimg.cn/orj360/001DQGfkgy1h46mjn19khj61o02yo1ky02.jpg'
  3. #content返回的是二进制的图片数据
  4. # text (字符串) content (二进制) json() (对象)
  5. img_data=requests.get(url=url).content
  6. with open('./tupian.jpg','wb') as fp: # w以写方式打开文件,b以二进制方式打开文件(不能单独使用,
  7. 以wb或者rb组合使用)
  8. fp.write(img_data)

正则解析

  1. import re
  2. import requests
  3. import os
  4. #创建一个文件夹,保存所有图片
  5. if not os.path.exists('./tupian'):
  6. os.mkdir('./tupian')
  7. url='https://tieba.baidu.com/f'
  8. header={'User-Agent':
  9. 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0'}
  10. #使用通用爬虫,对整张页面进行爬取
  11. page_text=requests.get(url=url,headers=header).text
  12. #使用聚焦爬虫对页面中所有图片进行提取(解析)
  13. ex='<div class="card_banner card_banner_link"><img src="(.*?)”id.*?</div>'
  14. img_src_list=re.findall(ex,page_text,re.S)
  15. #print(img_src_list)
  16. #拼接一个完整的图片url
  17. for src in img_src_list:
  18. src='http://'+src
  19. #请求到图片的二进制数据
  20. img_data=requests.get(url=src,headers=header).content
  21. #生成图片名称
  22. img_name=src.split('/')[-1]
  23. imgPath='./tupian'+img_name
  24. with open(imgPath,'wb') as fp:
  25. fp.write(img_data)
  26. print(img_data,'下载成功')

bs4解析

数据解析原理:1.标签定位 2.提取标签、标签属性中存储的数据值

bs4数据解析原理:

            1.实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中

            2.通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取

(需要安装bs4、lxml环境)

如何实例化BeautifulSoup对象:

  1. from bs4 import BeautifulSoup
  2. #对象实例化:
  3. # 1.将在本地的html文档中的数据加载到该对象中
  4. fp=open('./test.html','r',encoding='utf-8')
  5. soup= BeautifulSoup(fp,'lxml')
  6. # 2.将互联网上获取的页面源码加载到该对象中
  7. page_text=response.text
  8. soup=BeautifulSoup(page_text,'lxml')

 提供的用于数据解析的方法和属性:

(1)soup.tagName:返回的是文档中第一次出现的tagName对应的标签

 (2)soup.find():

         —find('tagName'):等同于soup.div

         —属性定位:suop.find('div',class_/id/attr='song')

(3)soup.find_all('tagName'):返回符号要求的所有标签(列表)

(4)select:

        select('某种选择器 ( id,class,标签...选择器 ) '),返回的是一个列表

         层级选择器:

         —soup.select('.tang>ul>li>a') :>表示的是一个层级

         —soup.select('.tang> ul a ') :空格表示的多个层级

  1. from bs4 import BeautifulSoup
  2. fp=open('./test.html','r',encoding='utf-8')
  3. soup= BeautifulSoup(fp,'lxml')
  4. print(soup)
  5. print(soup.a) #soup.tagName 返回的是html中第一次出现的tagName标签
  6. print(soup.div)
  7. print(soup.find('div')) #等同于print(soup.div)
  8. print(soup.find('div',class_='song'))
  9. print(soup.find_all('a'))
  10. print(soup.select('.tang'))
  11. print(soup.select('.tang>ul>li>a')[0])
  12. print(soup.select('.tang>ul a')[0])

 获取标签之间的文本数据:

soup.a.text /string /get_text()

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

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

  1. print(soup.find('div',class_='song').text) #可以获得div下的所有内容(返回字符串)
  2. print(soup.find('div',class_='song').string) #只能获取div下的直系内容

获取标签中属性值:

soup.a [ ' href属性名称 ' ]

 print(soup.select('.tang>ul a')[0]['href']) #获取a的属性值

 bs4解析案例

爬取三国演义小说所有的章节标题和章节内容 

  1. import requests
  2. from bs4 import BeautifulSoup
  3. url='https://sanguo.5000yan.com/'
  4. header={'User-Agent':
  5. 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0'}
  6. #对首页数据进行爬取
  7. page_text=requests.get(url=url,headers=header).text
  8. #在首页中解析出章节的标题和详情页的url
  9. #1.实例化BeautifulSoup对象,需要将页面源码数据加载到该对象中
  10. soup=BeautifulSoup(page_text,'lxml')
  11. #解析章节标题和详情页的url
  12. li_list=soup.select('.sidamingzhu-list-mulu>ul>li')
  13. fp=open('./sanguo.txt','w',encoding='utf-8')
  14. for li in li_list:
  15. title=li.a.string
  16. detail_url=li.a['href']
  17. #对详情页发起请求,解析出章节内容
  18. detail_page=requests.get(url=detail_url,headers=header).text
  19. #解析出详情页中相关的章节内容
  20. detail_soup=BeautifulSoup(detail_page,'lxml')
  21. div_tag=detail_soup.find('div',class_='grap')
  22. #解析到了章节的内容
  23. content=div_tag.text
  24. fp.write(title+':'+content+'\n')
  25. print(title,'爬取成功')

xpath解析(便捷高效、通用)

xpath解析原理:

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

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

如何实例化一个etree对象:

  1. from lxml import etree
  2. 1.将本地的html文档中的源码数据加载到etree对象中:
  3. etree.parse(filePath)
  4. 2.将从互联网上获取的源码数据加载到该对象中
  5. etree.HTML('page_text')
  6. xpath('xpath表达式')

 xpath表达式:

(1) / :表示的是从根节点开始定位。表示的是一个层级。

(2) // :表示的是多个层级。可以表示从任意位置开始定位。

(3)属性定位://div[@class='song']  tag[@atrrName="attrValue"]

(4)索引定位://div[@class="song"]/p[3]  索引是从1开始的

(5)取文本:

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

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

(6)取属性:

                /@attrName  ==>img/src

  1. from lxml import etree
  2. #实例化好了一个etree对象,且将被解析的源码加载到了该对象中
  3. tree=etree.parse('test.html')
  4. r=tree.xpath('/html/body/div')
  5. r1=tree.xpath('/html//div') #这三个表达式,返回结果一样,所以表达的含义一样
  6. r2=tree.xpath('//div')
  7. r3=tree.xpath('//div[@class="song"]/p[3]')
  8. #r4=tree.xpath('//div[@class="tang"]//li[5]/a')#标签定位
  9. r4=tree.xpath('//div[@class="tang"]//li[5]/a/text()')[0] #获取标签内文本内容,得到的是一个列表,用[0]取出内容
  10. r5=tree.xpath('//li[7]//text()') #这里用/text()不能获取文本,因为这个内容没有直系存储在li标签,但是用//text()就可以获取到
  11. r6=tree.xpath('//div[@class="tang"]//text()') #获取div下的所有内容
  12. #取属性
  13. r7=tree.xpath('//div[class="song"]/img/@src')

 xpath解析案例之二手房源

获取二手房的所有标题

  1. from lxml import etree
  2. import requests
  3. #爬取页面源码数据
  4. url='https://bj.58.com/ershoufang/'
  5. headers={'User-Agent':
  6. 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0'}
  7. page_text = requests.get(url = url,headers = headers).text
  8. tree = etree.HTML(page_text)
  9. li_List = tree.xpath('//section[@class = "list"]/div')
  10. fp = open('58.txt','w',encoding='utf-8')
  11. for li in li_List:
  12. title = li.xpath('./a/div[2]//div/h3/text()')[0]
  13. print(title)
  14. fp.write(title+'\n')

xpath解析之图片解析

  1. import os.path
  2. from lxml import etree
  3. import requests
  4. #爬取页面源码数据
  5. url='http://pic.netbian.com/'
  6. headers={'User-Agent':
  7. 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0'}
  8. page_text = requests.get(url = url,headers = headers).text
  9. tree = etree.HTML(page_text) #实例化一个etree对象
  10. li_List = tree.xpath('//div[@class="slist"]/ul/li')
  11. #创建一个文件夹
  12. if not os.path.exists('./pictures'):
  13. os.mkdir('./pictures')
  14. #遍历标签li里面的内容
  15. for li in li_List:
  16. img_src='http://pic.netbian.com'+li.xpath('./a/span/img/@src')[0]
  17. img_name=li.xpath('./a/span/img/@alt')[0]+'.jpg'
  18. #通用处理中文乱码的解决方案
  19. img_name=img_name.encode('iso-8859-1').decode('gbk')
  20. #print(img_name,img_src)
  21. #请求图片进行持久化存储
  22. img_data=requests.get(url=img_src,headers=headers).content
  23. img_path='./pictures'+img_name
  24. with open(img_path,'wb') as fp:
  25. fp.write(img_data)
  26. print('下载成功')

Day3

验证码识别

反爬机制:利用验证码。

识别验证码图片中的数据,用于模拟登陆操作。

识别验证码的操作:1.人工肉眼识别(不推荐)  2.第三方自动识别

举例:古诗文网验证码识别

使用打码平台识别验证码的编码流程:

        1.将验证码图片进行本地下载

        2.调用平台提供的示例代码进行图片数据识别

Day4

异步爬虫

异步爬虫的目的:在爬虫中使用异步实现高性能的数据爬取操作。

异步爬虫的方式:

      1.多线程,多进程(不建议):

                好处:可以为相关阻塞的操作单独开启线程或者进程,阻塞操作就可以异步执行。

                弊端:无法无限制的开启多线程或者多进程。

      2.线程池、进程池(适当使用):

                好处:可以降低系统对进程或者线程创建和销毁的一个频率,从而很好的降低系统开销。

                弊端:池中线程或进程的数量是有上限的。

        (使用原则:线程池处理的是阻塞且耗时的操作)

        3.单线程+异步协程 (推荐):

                event_loop:事件循环,相当于一个无限循环,我们可以把一些函数注册到这个事件循环上,当满足某些条件时,函数就会被循环执行。

                coroutine:协程对象,我们可以将协程对象注册到事件循环中,它会被事件循环调用。我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象。

                task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。

                future:代表将来执行或还没有执行的任务,实际上和 task 没有本质区别。

                async:定义一个协程。

                await:用来挂起阻塞方法的执行。

单线程串行:

  1. import time
  2. #使用单线程串行方式执行
  3. def get_page(str):
  4. print('正在下载:',str)
  5. time.sleep(2)
  6. print('下载成功:',str)
  7. name_list=['qe','eefew','ddds']
  8. start_time=time.time()
  9. for i in range(len(name_list)):
  10. get_page(name_list)
  11. end_time=time.time()
  12. print('%d,second'% (end_time,start_time))

 线程池方式执行:

  1. import time
  2. #导入线程池模块对应的类
  3. for multiprocessing.dummy import Pool
  4. #使用线程池方式执行
  5. start_time = time.time()
  6. def get_page(str):
  7. print('正在下载:',str)
  8. time.sleep(2)
  9. print('下载成功:',str)
  10. name_list=['qe','eefew','ddds']
  11. #实例化一个线程池对象
  12. pool=Pool(4)
  13. #将列表中每个元素传递给get_page进行处理
  14. pool.map(get_page,name_list)
  15. end_time=time.time()
  16. print(end_time-start_time)

协程:

  1. import asyncio
  2. async def request(url):
  3. print('正在请求的url是',url)
  4. print('请求成功',url)
  5. return url
  6. #async修饰的函数,调用之后返回的一个协程对象
  7. c=request('www.baidu.com')
  8. #创建一个事件循环对象
  9. #loop=asyncio.get_event_loop()
  10. #将协程对象注册到loop中,然后启动loop
  11. #loop.run_until_complete(c)
  12. #task的使用
  13. #loop=asyncio.get_event_loop()
  14. #基于loop创建了一个task对象
  15. #task=loop.create_task(c)
  16. #print(task)
  17. #loop.run_until_complete(task)
  18. #print(task)
  19. #future的使用
  20. # loop=asyncio.get_event_loop()
  21. # task=asyncio.ensure_future(c)
  22. # print(task)
  23. # loop.run_until_complete(task)
  24. # print(task)
  25. def callback_func(task):
  26. #result返回的就是任务对象中封装的协程对象对应函数的返回值
  27. print(task.result())
  28. #绑定回调
  29. loop=asyncio.get_event_loop()
  30. task=asyncio.ensure_future(c)
  31. #将回调函数绑定到任务对象中
  32. task.add_done_callback(callback_func())
  33. loop.run_until_complete(task)
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/101684
推荐阅读
相关标签
  

闽ICP备14008679号