一:爬取流程
1.准备工作:
通过浏览器查看目标网页
2.获取数据:
通过HTTP库向目标网站发送请求,请求可以包含header等信息,如果网站能正常响应,会得到一个REsponse,这就是网页的内容
3.解析内容:
4.保存数据:
可以保存为txt文本,也可以保存为数据库,也可以保存为你想要保存的形式
二:准备工作:
-
允许代码出现中文:
#-*-coding:utf-8-*-
(可以保证在代码中可以出现中文) -
可以加入main函数用于测试程序:
if_name=="_main_":#规范 eg: if __name__=="__main__":#当程序执行的时候 #调用main函数 def main(): print("hello")
-
引入库:import
#引入系统模块: import os import sys #引入第三方模块:需要外部引入 import re #正则表达式进行文字匹配 import urllib #制定url,获取网页数据 import xlwt #进行excel操作 import bs4 #网页解析,获取数据 from bs4 import BeautifulSoup #网页解析,获取数据 import sqlLite3 #进行SQLite数据库操作 #如何操作,进行外部引入: terminal->打开控制台->pip ps4/re/urllib/xlwt#临时安装 File->setting->project+名字->project interpreter->右上角+号->搜索框搜索引入的包,并添加
-
请求数据:post和get请求:
import urllib.request import urllib.parse #模拟浏览器,封装数据所用的包 #请求网页,获取一个get对象 response=urllib.request.urlopen("http://www.baidu.com")#open一个网页 print(response.read().decode('utf-8'))#输出读取对象的信息,而不是直接输出对象名,注意为了王编码更加流畅,使用utf-8解码 #post请求,一般用在模拟用户网站登录的时候,必须给一个封装后的表单,否则直接post是不允许的 #这里将数据使用二进制转换,并以utf-8的格式封装到data,并使用parse包封装成浏览器发送请求 data=bytes(urllib.parse.urlencode({"password":"132456"}),encoding="ut #使用post请求的时候,必须在最后写明post,并且把封装好的表单写上 response=urllib.request.urlopen("http://httpbin.org/post",data=data) #get请求,同上只需要换成get就好了
-
超时现象(也就是网站发现了是爬虫,拒绝访问)
#使用try块,捕获异常,并在获取request对象的时候,加上timeout属性(检测执行时间) try: response=urllib.request.urlopen("http://www.baidu.com",timeout=2) print(response.read().decode('utf-8')) except URLError as E: print("URLError")
-
获取header响应头
response.getheaders()#获取所有header的表单 response.getheader("Server").decode('utf-8')#获取指定的header的值,以utf-8解码
-
当遇到418的时候,User-Agent需要改变一下
#url:请求地址,data:封装程浏览器发送的表单,headers:返回的响应头,method:响应 url="http://baidu.com" headers={ User-Agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36 Edg/85.0.564.63" } data=bytes(urllib.parse.urlencode({"password":"132456"}),encoding="utf-8") req=urllib.request.Request(url=url,data=data,headers=headers,method ="POST") response=urllib.request.urlopen(req)#注意:这里不是传地址,而是直接传了一个req对象,里面包含了所需要的的素有信息 print(response.read().decode("utf-8") #User-Agent所在位置:F12->NetWork->Header->Request Header->User-Agent后面所有的内容
三:获取数据:(可以使用for循环,循环调用实现翻页效果)
def askURL(url): #User-Agent必须与其完全一致才行 head={#模拟浏览器头部信息,向服务器发送消息 User-Agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36 Edg/85.0.564.63" } #这个请求标头request是为了给response服务以及传参的 request =urllib.request.Request(url,headers=head) html="" try: response=urllib.request.urlopen(request) html=response.read().decode("utf-8")#以html的方式读取数据 print(html) except urllib.error.URLError as e: if hasatter(e,"code"):#错误1 print(e.code) if hasatter(e,"reason"):#错误2 print(e.reason)
重点:BeautifulSoup使用方法:
file=open("./baidu.html","rb") html=file.read() #这里是核心,将筛选器bs对象创建出来,可以是html对象,也可以是xml对象,自动补全标签 bs=BeautifulSoup(html."html.paser")#第一个参数是将转换的类型,第二个参数是固定格式(文件.paser) 1.获取Tag标签及其内容: print(bs.title) print(bs.a) print(bs.head) 2.NavigableString,获取标签里面的内容(字符串) print(bs.title.tring) print(bs.a.string) 3.BeautifulSoup:获取标签整个文档内容 print(bs) 4.attr:获取标签下所存在的元素成员,并且以表单的形式返回 print(bs.a.attrs) #输出:{‘class':['manbv'],'href':'ahsfiasf'} 5.Comment:是一个特殊的NavigableString,但是输出的时候不包含注释符号 print(bs.a.string) 6.contents:遍历文件树 #tag的.content属性可以将tag的子节点以列表的方式输出 print(bs.head.contents) #用列表索引来获取他的某一个元素 print(bs.head.contents[1]) 7.遍历文档树: soup = BeautifulSoup(html_doc,'lxml') # 1、直接使用 print(soup.html) print(type(soup.html)) #类型变成了element_tag print(soup.a) # 2、获取标签的名称 print(soup.a.name) # 3、获取标签的属性 print(soup.a.attrs) # 4、获取标签的内容 print(soup.p.text) # 5、嵌套选择 print(soup.html.body.p) # 6、子节点、子孙节点 print(soup.p.children) # 7、父节点、祖先节点 print(soup.b.parent) print(soup.b.parents) 8.搜索文档树: 格式: 标签查找与属性查找: find与findall find找一个 findall找所有 标签: - 字符串过滤器 字符串全局匹配 name 属性匹配 attrs 属性查找匹配 text 文本匹配 - 正则过滤器 re模块匹配 - 列表过滤器 列表内的数据匹配 - bool过滤器 True匹配 - 方法过滤器 用于一些要的属性以及不需要的属性查找。 属性: - class_ - id # 第一个参数是解析文本 # 第二个参数是解析器 soup = BeautifulSoup(html_doc, 'lxml') # 1、字符串 # find的默认参数 第一个是name、第二个是attrs、第四个是text # name: 根据标签名匹配节点 print(soup.find('p')) # 获取第一个p标签 print(soup.find_all(name='p')) # 获取所有的p标签 # attrs: 根据属性查找匹配节点 print(soup.find(attrs={'id': 'p'})) # 查找id为p的标签 print(soup.find_all(attrs={'class': 'sister'})) # 查找class为sister的所有标签 # text: 根据文本匹配文档树内的文本 # 推荐配合其他匹配规则使用,否则毫无意义 print(soup.find(text='$37')) # 查找标签内为$37的文本 # name与text配合使用 print(soup.find_all(name='p', text='$37')) # 查找所有文本为$37的p标签 # name与attrs配合使用 print(soup.find(name='a', attrs={'id': 'link2'})) # 查找第一个id为link2的a标签 # attrs与text配合使用 print(soup.find_all(attrs={'id': 'link2'}, text='Lacie')) # 查找所有id为link2,文本为Lacie的标签 # name、attrs、text组合使用 print(soup.find_all(name='a', attrs={'id': 'link3'}, text='Tillie')) # 查找所有id为link3,文本为Tillie的a标签 # 2、正则 print(soup.find(name=re.compile('a'))) # 通过第一个标签名带有a的节点 print(soup.find_all(attrs={'id': re.compile('link')})) # 匹配所有id名带有link的节点 print(soup.find_all(text=re.compile('and'))) # 匹配所有文本带有"and"的节点 # 3、列表 (列表内可以匹配多个) print(soup.find_all(name=['a', re.compile('e')])) # 匹配所有a标签节点与所有标签中带有e的节点 print(soup.find_all(text=['$'])) # 找不到,因为$是精确查找 print(soup.find_all(text=['$37'])) # 查找$37文本,这样查找是没有意义的 print(soup.find_all(text=[re.compile('$')])) # 正则中$是特殊字符,所以需要转义 # 4、bool print(soup.find_all(name=True)) # 查找所有有标签名的节点 print(soup.find_all(attrs={'id': True})) # 查找所有有id的节点 print(soup.find_all(text=True)) # 查找所有文本 # 5、方法 # 写一个只要有class没有id的a标签的函数 def has_class_not_id(arg): if arg.name == 'a' and arg.has_attr('class') and not arg.has_attr('id'): return arg.name print(soup.find_all(name=has_class_not_id)) # 通过has_class_not_id的函数匹配节点 # 6、标签与属性查找 # 标签 print(soup.find_all(attrs={'class': 'sister'})) # 属性 # 根据class属性查找,因为class是关键字,所以后面需要加下划线 print(soup.find_all(class_='sister')) # 根据id属性查找 print(soup.find_all(id='link2'))