打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
数据采集

0.爬虫基本原理

爬虫是 模拟用户在浏览器或者App应用上的操作,把操作的过程、实现自动化的程序

当我们在浏览器中输入一个url后回车,后台会发生什么?比如说你输入https://www.baidu.com

简单来说这段过程发生了以下四个步骤:

  • 查找域名对应的IP地址。
    浏览器首先访问的是DNS(Domain Name System,域名系统),dns的主要工作就是把域名转换成相应的IP地址
  • 向IP对应的服务器发送请求。
  • 服务器响应请求,发回网页内容。
  • 浏览器显示网页内容。
01-webdns.jpg

网络爬虫要做的,简单来说,就是实现浏览器的功能。通过指定url,直接返回给用户所需要的数据, 而不需要一步步人工去操纵浏览器获取。

(1).浏览器是如何发送和接收这个数据呢?

HTTP协议(HyperText Transfer Protocol,超文本传输协议)目的是为了提供一种发布和接收HTML(HyperText Markup Language)页面的方法。

HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。

(2).爬虫基本思路

(1).通过URL或者文件获取网页, (2).分析要爬取的目标内容所在的位置 (3).用元素选择器(re、BeautifulSoup、Xpath等)快速提取(Raw)目标内容 (4).处理提取出来的目标内容 (通常整理合成一个 Json) (5).存储处理好的目标内容(比如放到 MongoDB、MySQL 之类的数据库,或者写进文件里.)

1.静态本地网页与json文件爬取演示

(1).html网页抓取

import urllib.request as re
from bs4 import BeautifulSoup
# 1.使用urllib的request模块,打开一个带有html页面的链接,此时获取的只是一个链接对象
response = re.urlopen('file:///D:/Project/Python/jyputerTest/Spider/Source/demo01.html')
# 2.从连接对象中将网页源代码字符串获取到,此时是没有经过格式化的
html = response.read()
# 3.通过 BeautifulSoup 对网页源代码字符串进行解析
soup = BeautifulSoup(html)
# 4.我们就可以从BeautifulSoup中直接使用标签名作为参数 去直接获取对应 标签 中的数据
soup.find('tr')
soup.find_all('tr')

(2).json数据读取

import urllib.request as re # 此时我们解析json使用的模版是json import json # 1.同样此时获取我们文件的连接 response = re.urlopen('file:///D:/Project/Python/jyputerTest/Spider/Source/demo02.json') # 2.将连接中的数据读取为源字符串 jsonString = response.read() # 3.加载数据为json,同时对读取到的json字符串做一个解码 jsonObject = json.loads(jsonString.decode()) # 4.对json中的数据进行值的获取(分不同的层级) jsonObject['employees'] # 根路径 jsonObject['employees'][0] # 获取列表中的第一个元素 jsonObject['employees'][0]['firstName'] # 获取字典中指定的key对应的值(value)

2.爬虫实战:7日天气预报 爬取

本次实战主要是使用 request库 和 BeautifulSoup 库进行数据的爬取

(1).实战原理

1),Requests 简介

request库是一个非常好用的请求发送包,它可以自动封装底层python 的网络请求。


request常用方法及说明.jpg

其中我们本次课程中是使用的:Requests.get()方法
Requests库的get()方法主要用于获取HTML网页,相当于HTTP的GET。其返回对象response的常用属性如下表所示,我们可通过这些属性获取要访问域名的基本信息。

2),BeautifulSoup 简介

BeautifulSoup库是用Python语言编写一个HTML/XML的解释器。它可以很好地处理不规范的标记并生成剖析树,其本身提供了简单又常用的导航、搜索以及修改剖析树的操作,利用它可以大大缩减编程时间。

简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据。

Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。

BeautifulSoup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果我们不安装它,则 Python 会使用 Python默认的解析器,lxml 解析器更加强大,速度更快,推荐使用lxml 解析器。


BeautifulSoup支持的解析器.png

3),网页信息查找与提取

我们使用Chrome浏览器,对于要爬取的网页,可以按F12进入调试模式,也可以选择相应信息右键'检查',亦可进入调试模式,而且直接到达该信息HTML位置,更为方便。

(2).实战代码

# 导入requests模块和bs4模块
import requests
from bs4 import BeautifulSoup

# 加入请求头,防止网站监测出来我们是爬虫,所以都必须要引入请求;对于有需要 登录 的页面需要加上cookices,那么直接在header字典中将 ' 'Cookie': '你的cookie' '添加进去
header={
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
# 引入要爬取的网页的url
url = 'http://www.weather.com.cn/weather/101120101.shtml'

# 1、获取网页的响应
# url,请求头,设置
response = requests.get(url, headers=header,timeout=30)
# 2,当网页获取成功的之后,设置网页的编码格式,方式出现中文的乱码
response.encoding='utf-8'

# 3,从获取到的文本连接中获取对应的网页源代码字符串
data= response.text
# print(text)

# 4,通过 BeautifulSoup 对网页源代码字符串进行解析;第二个参数是:指定 BeautifulSoup 使用什么格式进行解析(这里使用的是lxml :在你安装BeautifulSoup的时候默认是没有这个库的,需要你手动去安装 pip install lxml)
soup = BeautifulSoup(data,'lxml')
# print(soup)

# find()的作用是只去找 指定样式中 第一个出现的
ul = soup.find(class_='t clearfix')
# print(ul)

ul_li = ul.find_all('li')
# 遍历打印所有的元素
for item in ul_li:
    # print(item)
    # 根据标签获取值
    # 1.获取当前日期
    day = item.find('h1').text
    # 2.获取当前日期下对应的天气
    wea = item.find(class_='wea').text
    # 3.获取当前日期下对应温度区间
    tem = item.find(class_='tem').text
    # 如果想获取最低气温(可以直接使用下标的方式直接去处理温度区间中的值)
    # print(tem[4:])
    # 4.取风向,使用find函数默认是在item中取第一次出现的em标签;对应的可以直接再去取span标签的值,就直接用“.标签案名”的方式进行获取
    ws = item.find('em').span.attrs['title']
    # 5.把两个风向都取出来的话,可以使用findall,此时先把所有的带有风向的span标签获取出来
    ws_all_span = item.find('em').find_all('span')
    # 使用 推导式 的方式将所有风向获取出来,并返回一个列表
    ws_all = [ws['title'] for ws in ws_all_span]
    # 6.获取风力,先拿到class,再拿到对应的i,对应的文本,然后将 '<' 做一个替换 '小于'
    win = item.find(class_='win').i.text.replace('<','小于')
    
    print('-----------------------------begin---------------------------------------------------------------------')
    print('-----------------------------1:日期-----------------------------------------------------------------')
    print(day)
    print('-----------------------------2:天气-----------------------------------------------------------------')
    print(wea)
    print('-----------------------------3:温度-----------------------------------------------------------------')
    print(tem)
    print('-----------------------------4:只获取第一个风向-----------------------------------------------------------')
    print(ws)
    print('-----------------------------5:两个风向都取出来-----------------------------------------------------')
    # 在输出的时候使用sep指定分隔符
    print(ws_all[0],ws_all[1],sep=',')
    print('-----------------------------6:风级-----------------------------------------------------------------')
    print(win)
    print('-----------------------------end---------------------------------------------------------------------')

(3).find() 参数总结

每一次执行find() 之后的返回值,仍然是一个对象(bs4.element.Tag),还可以继续调用对象中的 '.' 方法。

参数 对应含义
find('XXX') 传入默认参数表示:查询指定 'XXX' 标签第一次出现的位置对应的属性值
find_all('XXX') 传入默认参数表示:查询指定 'XXX' 标签所有出现的位置对应的属性值
find(class_='XXX') 传入 'class_ ' 参数表示:查询指定CSS属性为 'XXX' 的值
find(id='XXX') c传入'id' 参数表示:查找指定id属性为 'XXX' 的值
find('XXX').span 配合 '.' 参数的时候,来获取 'XXX' 标签下嵌套的 'span' 标签(在之后的代码中可以对Span标签中的值进行进一步的值的获取)
find('XXX').span.attrs['title'] 配合 'attrs['xxx']' 参数的使用,来获取嵌套在'XXX' 标签下对应 'span '标签中指定的属性值,例如可以获取 'span' 标签中的 'title' 属性的值;同理:如果此时的 'span' 标签 换成 'a' 标签,那么此时再使用 '.attrs['href']' 就可以获取 'a' 标签中的 'href' 属性的值,从而进行连接的跳转。
find('XXX').span['title'] 和上一个表格中的实现效果是等价的

(4).select() 选择器参数总结

在CSS中,标签名不加任何修饰,类名前加点,id名前加 #,在这里我们也可以利用类似的方法来筛选元素,用到的方法是 soup.select(),返回类型是 list。

以下的 select 方法返回的结果都是列表形式,可以遍历形式输出,然后用 get_text() 方法来获取它的内容;获取将其中的值取出来,此时其类型仍然是一个对象(bs4.element.Tag)

参数 对应含义
soup.select('xxx') 通过标签名进行查找
soup.select('.xxx') 通过类名进行查找,也就是class属性
soup.select('#xxx') 根据id名查找
soup.select('p #xxx') 组合查找即和写 class 文件时,标签名与类名、id名进行的组合原理是一样的。例如查找 p 标签中,id 等于 xxx 的内容,二者需要用空格分开
soup.select('head > title') 直接子标签查询,也是查询指定标签下的某一个标签。例如查询 p 标签下的 title 标签
soup.select('a[class='sister']') 根据属性查找:查找时还可以加入属性元素,属性需要用中括号括起来,注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到。

3.re(正则表达式)的使用与图片文件的下载

此时以 '2.爬虫实战:7日天气预报 爬取' 的结果为例进行数据的保存:
此时已经有了从网页中获取的html文本

  • 爬虫代码
# 导入requests模块和bs4模块 import requests from bs4 import BeautifulSoup # 加入请求头,防止网站监测出来我们是爬虫,所以都必须要引入请求;对于有需要 登录 的页面需要加上cookices,那么直接在header字典中将 ' 'Cookie': '你的cookie' '添加进去 header={ 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36' } # 引入要爬取的网页的url url = 'http://www.weather.com.cn/weather/101120101.shtml' # 1、获取网页的响应 # url,请求头,设置访问超时 response = requests.get(url, headers=header,timeout=30) # 2,当网页获取成功的之后,设置网页的编码格式,方式出现中文的乱码 response.encoding='utf-8' # 3,从获取到的文本连接中获取对应的网页源代码字符串 data= response.text print(data)
  • 图片文件的保存
# 使用正则进行匹配
import re
# 此时的正则表达式的含义是:以 src=开头,然后 .png 结尾,中间是啥都行,而且此时是懒惰匹配
images = re.findall(r'src='(.*?\.png)'',data)

# 1.单张图片的保存
response = requests.get(images[0])
img = response.content
title=0
path = r'./picture/%s.jpg'%(title)
with open(path,'wb') as f:
    f.write(img)
    
# 2.批量url连接图片的保存 
# 每个文件的命令方式是从 0 开始递增的
count = 0
for url in images:
    response = requests.get(url)
    img = response.content
    count = count + 1
    # 使用C语言的格式(类似与占位符的方式)进行拼接 路径字符串 (此时的路径需要提前创建!!!或者再引入os库将创建文件夹)
    path = r'./picture/%s.jpg'%(count)
    # 以写和二进制的权限,打开文件,此时的文件会自动创建
    with open(path,'wb') as f:
        # 使用写的方式将文件下载到指定的路径汇总
        f.write(img)

(1),正则表达式

1).常用元字符:

代码 说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束

2),字符转义

如果想查找元字符本身的话,得使用\来取消其特殊含义。比如.可以使用 \.的方式进行转义。

3).重复次数:常用限定符

代码/语法 说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

4),字符类

对于需要匹配多个字符的时候,我们需要通过列表的方式进行指定,可以指定多个不同的字符,例如(a,e,i,o,u);或者是指定一个区间,例如:([0-9])

5),反义代码

代码/语法 说明
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符

6),贪婪与懒惰

  • 当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪*匹配。

  • 有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:

    a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。

代码/语法 说明
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

4.爬虫实战:豆瓣电影信息 爬取

本次实战主要是使用 request库与 Xpath库进行操作

(1).实战原理

1),Xpath 简介

Xpath 即为 XML 路径语言(XML Path Language),它是一种用来确定 XML 文档中某部分位置的语言。Xpath 基于 XML 的树状结构,提供在数据结构树中找寻节点的能力。起初 Xpath 的提出的初衷是将其作为一个通用的、介于 Xpointer 与 XSL 间的语法模型。但是Xpath 很快的被开发者采用来当作小型查询语言。

Xpath解析网页的流程:


Xpath流程简介.jpg

1.首先通过Requests库获取网页数据;

2.通过网页解析,得到想要的数据或者新的链接;

3.网页解析可以通过 Xpath 解析网页,然后通过定位元素,然后再右键使用Copy的方式获取元素的Xpath信息并获得文本:

file=s.xpath('元素的Xpath信息/text()')

(2).实战代码

# 导入requests模块和bs4模块 import requests from lxml import etree # 引入要爬取的网页的url url = 'https://movie.douban.com/subject/1292052/' # 加入请求头,防止网站监测出来我们是爬虫,所以都必须要引入请求;对于有需要 登录 的页面需要加上cookices,那么直接在header字典中将 ' 'Cookie': '你的cookie' '添加进去 header={ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36' } # 1、获取网页的响应 # url,请求头,设置访问超时时间 response = requests.get(url, headers=header,timeout=30) # 2,当网页获取成功的之后,设置网页的编码格式,方式出现中文的乱码 response.encoding='utf-8' # 3,从获取到的文本连接中获取对应的网页源代码字符串 data = response.text # 4.对获取到的网页源代码字符串使用etree解析 s=etree.HTML(data) # 5.通过从网页中Copy的Xpath路径,依次获取电影名称、导演、主演、时长信息 film=s.xpath('//*[@id='content']/h1/span[1]/text()') director=s.xpath('//*[@id='info']/span[1]/span[2]/a/text()') actor=s.xpath('//*[@id='info']/span[3]/span[2]/a/text()') time=s.xpath('//*[@id='info']/span[13]/text()') # 6.显示获取的信息内容 print('name:',film) print('director:',director) print('actors:',actor) print('duration:',time)

(3).Xpath代码的来源

获取电影名称
元素的Xpath信息是需要我们手动获取的,获取方式为:定位目标元素(电影名称:肖申克的救赎),在网站上选取的目标元素上依次点击:右键 > 检查,按住快捷键“shift+ctrl+c”,移动鼠标到对应的元素时即可看到对应网页代码:

在网页中查看指定标签的Xpath_01.png

在电影标题对应的代码上依次点击 右键 > Copy > Copy XPath,获取电影名称的Xpath:


在网页中查看指定标签的Xpath_02.png

此时得到的标签示例 '//*[@id='content']/h1/span[1]'

# 1,直接将获取到Xpath打印出来,得到的是一个元素
print(s.xpath('//*[@id='content']/h1/span[1]'))
# 输出结果:[<Element span at 0x1a4e1c0afc8>]

# 2,可以再追加'/text()',获取元素中对应的值
print(s.xpath('//*[@id='content']/h1/span[1]/text()'))
# 输出结果:['肖申克的救赎 The Shawshank Redemption']

同理可以得到其他元素的标签!!!

5.文本文件的保存

(1).保存字符串到本地txt文件中

此时以 '4.爬虫实战:豆瓣电影信息 爬取' 的结果为例进行数据的保存:
此时已经有了 “film”,“director”,“actor”,“time”变量对应的属性值

  • 爬虫代码
# 导入requests模块和bs4模块 import requests from lxml import etree # 引入要爬取的网页的url url = 'https://movie.douban.com/subject/1292052/' # 加入请求头,防止网站监测出来我们是爬虫,所以都必须要引入请求;对于有需要 登录 的页面需要加上cookices,那么直接在header字典中将 ' 'Cookie': '你的cookie' '添加进去 header={ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36' } # 1、获取网页的响应 # url,请求头,请求延迟(时间):主要是在多批次访问的时候,有一个停顿时间,可以防止网站监测为爬虫,也就是伪造一个真实的人的请求 response = requests.get(url, headers=header,timeout=30) # 2,当网页获取成功的之后,设置网页的编码格式,方式出现中文的乱码 response.encoding='utf-8' # 3,从获取到的文本连接中获取对应的网页源代码字符串 data = response.text # 4.对获取到的网页源代码字符串使用etree解析 s=etree.HTML(data) # 5.通过从网页中Copy的Xpath路径,依次获取电影名称、导演、主演、时长信息 film=s.xpath('//*[@id='content']/h1/span[1]/text()') director=s.xpath('//*[@id='info']/span[1]/span[2]/a/text()') actor=s.xpath('//*[@id='info']/span[3]/span[2]/a/text()') time=s.xpath('//*[@id='info']/span[13]/text()')
  • 文件保存代码
# 对最后文件的输出内容进行重新格式化拼接为一个字符串,然后进行保存
# 1,首先测试输出效果
print('1:name: {},\n2:director: {},\n3:actor: {},\n4:time: {}'.format(film[0],director[0],actor,time[0]))
# 2,赋于变量进行保存,然后测试输出
outData = '1:name: {},\n2:director: {},\n3:actor: {},\n4:time: {}'.format(film[0],director[0],actor,time[0])
print(outData)
# 3,连接本地文件系统,进行文件夹与文件的创建
# 4,首先判断要输出的文件是否存在,如果存在则直接进入到指定文件夹中,不存在则创建文件夹
import os
if os.path.exists('./output'):
    os.chdir('./output')
else:
    os.mkdir('./output')
    os.chdir('./output')
# 5,打开一个文件(若文件不存在则创建一个),然后向文件中写入数据,最后关闭与本地文件系统的连接
# 此时就是提前创建一个带有指定路径和文件的对象,然后再调用写操作,最后将写操作关闭
myfile = open('./out.txt','w',encoding='utf-8')
myfile.write(outData)
myfile.close()

# 6,如果想追加数据,直接打开文件,然后通过第二个参数指定模式为追加
# 注意此时是在创建文件对象的同时,通过文件对象带调用写操作,
with open('./out.txt','a',encoding='utf-8') as file:
    file.write('\n123465')

(2).保存字符串到Mysql数据库中

# 1,首先在Mysql中建立你要导出的数据库和根据字段的内容创建数 ''' create databases test; use test; create table spiderTest(film varchar(100),director varchar(100),actor varchar(100),time varchar(100)) CHARSET=utf8; ''' # 2,然后获取数据库的连接 # 3,使用 execute()方法,执行插入语句将内容写入到数据库中
import pymysql   # 导入相应操作Mysql的库文件
 
conn = pymysql.connect(host='localhost',user='root',password='111111',db='test',port=3306,charset='utf8')
cursor=conn.cursor()    # 连接数据库及光标

# 注意此时对于演员的数据过长,所以只是截取了第一个数据写入的
cursor.execute('insert into spiderTest(film,director,actor,time) values(%s,%s,%s,%s)',(str(film[0]),str(director[0]),str(actor[0]),str(time[0])))
# 当执行完插入语句后需要手动提交,才会生效。
conn.commit()
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Python网络爬虫四大选择器(正则表达式、BS4、Xpath、CSS)总结
Python私活300元,爬虫批量获取新浪博客文章存储到Word文件
用Python写简单爬虫
Python的爬虫包Beautiful Soup中用正则表达式来搜索
python爬虫之定位网页元素的三种方式
小白搞爬虫
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服