爬虫基础知识
概述
定义:
爬虫的本质:通过编写程序模拟浏览器上网,获取页面源码或在动态数据,通过解析返回结果获取想要的数据的过程
分类:
- 通用爬虫:获取整张页面的源码数据
- 聚焦爬虫:获取指定区域的数据,如页面加载时的一些动态数据
- 增量式爬虫:获取网站更新的数据
常见的反扒机制:
- robots.txt协议:可以在网页后面加上robots.txt,该协议规定允许哪些服务器爬取数据,但该协议像"无人地摊一样".(解决方法,当作看不到即可)
- UA协议:在请求头中有一个User-agent字段,该字段的值是关于浏览器的信息,有些网站没有该字段不让访问(解决方法:复制浏览器的请求ua字段)
- 验证码:通过输入验证码才能访问(采用云打码等第三方平台解码,然后填写到验证码输入框
- cookie:没有携带cookie的不允许访问(采用自动cookie处理即requests模块的Session实例化的对象代替requests)
- 检测ip:对于短期内多次数访问封ip(在requests请求中添加代理ip参数即可)
- 动态参数:通过给之前的网页分配一个隐藏的参数,页面请求是需要携带该参数,否则不允许访问(解析源码获取该参数)
- 动态加载数据:用户在浏览器的操作加载不同数据,(通过获取动态加载数据的url请求获取队形数据)
requests模块
requses模块是可以通过模拟浏览器发送请求获取页面的响应数据,安装模块:pip install requests
使用步骤:
- 指定url,请求头以及请求数据
- 向服务器发送数据
- 获取和解析数据
- 持久化存储
示例
# 需求:爬取搜狗指定词条搜索后的页面数据 import requests # 1. 指定URL url = "https://www.baidu.com/" # 请求头数据 headers = { # 从浏览器复制过来的UA "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36" } #请求数据,可根据实际情况决定要不要 data = { "kw":"cat" } # 2. 向服务器发送请求,该请求是get请求,如果是pose请求则如注释所示 response = requests.get(url=url, headers=headers,params=data) # response = requests.post(url=url, data=data, headers=headers) # 3. 获取响应数据, page_text = response.text # 如果返回的是json数据 # data = response.json() # 如果返回的是视频或者图片等文件数据 # data = response.content # 4. 持久化存储 with open('./lijie.html', 'w', encoding="utf-8") as f: f.write(page_text)
页面数据解析
当页面返回json()数据和content数据,可以直接将数据存储到本地,但如果返回的数据是text数据,通常返回的是html源码,这个时候就需要解析源码获取数据,常用的解析源码模块有bs4和lxml,其中,bs4模块是基于lxml模块的,所以想要使用就必须安装两个模块,通过pip install ba4和pip install lxml下载安装
bs4
通过模块的BeautifulSoup类来实例化一个对象soup
常用方法和属性
- 根据标签名查找标签:soup.a
- 获取标签属性:soup.a.attrs(获取所有属性名和值),soup.a.attrs["href"](获取a标签的href属性),soup.a["href"](获取href属性)
- 获取文本内容:soup.string(不能获取标签内部的标签的文本属性),soup.text/soup.get_text()(获取标签下所有文本)
- 获取第一个符合要求的标签:soup.find("标签名",属性名=“属性值”),如soup.find("a", class="test")
- 查找所有符合要求的标签:soup.find_all("标签名",属性名=“属性值”),如soup.find_all("a", class="test")
- 通过选择器查找标签:soup.select(标签选择器) #css中支持的这类基本都支持
案例
# 爬取诗词名句网http://www.shicimingju.com/book/index.html 前100个小说的所有内容, 每一个文章存一个txt文件, 并保存到文件夹中 import requests,os from bs4 import BeautifulSoup # 请求url,获取全部书籍都信息 url = "http://www.shicimingju.com/book/index.html" headers = { # UA伪装 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36" } response_text = requests.get(url=url,headers=headers).text # 实例化一个soup对象 soup = BeautifulSoup(response_text,"lxml") # 通过选择器获取标签多个列表 book_detail_list = soup.select(".bookmark-list ul li a") book_title = [] # 获取标签后得到标签的属性和文本 for i in book_detail_list: dic = { "title":i.text, "url":"http://www.shicimingju.com" + i.attrs["href"] } book_title.append(dic) # 创建保存数据的目录 if not os.path.exists("./book"): os.mkdir("./book") # 循环获取书籍的内容 for book in book_title: # 获取书籍rl book_url = book["url"] # 获取某本书籍的源码 book_data = requests.get(url=book_url,headers=headers).text # 判断之前是否以及爬取过 if os.path.exists("./book/" + book["title"] + ".txt"): continue # 实例化一个书籍的soup对象 chapter_soup = BeautifulSoup(book_data,"lxml") # 查看书籍章节信息 chapter_detail_list = chapter_soup.select(".book-mulu ul li a") filename = "book/"+book["title"] + ".txt" f = open(filename,"w",encoding="utf-8") # 获取书籍每章内容并保存在本地 for i in chapter_detail_list: chapter_url = "http://www.shicimingju.com" + i.attrs["href"] response_data = requests.get(url=chapter_url,headers=headers).text soup = BeautifulSoup(response_data,"lxml") if len(soup.select(".www-main-container")) > 0: continue data = soup.select(".www-main-container")[0].text f.write(data) f.write("\r\n") f.close()
lxml
通过该模块解析数据好处是通用性强,通过模块提供的etree类实例化一个类对象tree,通过该对象加载数据后的xpath方法可以定位到标签,然后通过方法或属性来得到数据
实例化对象:tree = etree()
加载数据:tree.HTML(response_text)
定位数据:tree.xpath('//div[@id="test"]/div/p/a')
获取文本:tree.xpath('//div[@id="test"]/div/p/a/text()').extract()
获取属性:tree.xpath('//div[@id="test"]/div/p/a/@href').extract()
代码解析://后面的div表示定位到div标签,[]内部写的是标签属性,后面的/div/p/a/表示定位到div标签下的div标签下的p标签下的a标签,text()获取文本属性的对象,@href获取a标签的href属性对象,extract表是将对象转化成列表,通过列表就可以获取值,示例
# 爬取梨视频里面体育版块最热和最新的视频(.mp4的格式)并下载到本地, 保存到文件夹中https://www.pearvideo.com/category_9 import requests,os from lxml import etree # 指定url url = "https://www.pearvideo.com/category_4" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36" } # 获取源码 response_text = requests.get(url=url,headers=headers).text # 正则表达式 ex = 'srcUrl="(.*?)".*?vdoUrl=srcUrl' # 实例化etree对象 tree = etree.HTML(response_text) # 获取所有视频详情页的url, | 代表或运算 tree_list = tree.xpath('//ul[@class="listvideo-list clearfix"]/li/div/a/@href | //ul[@class="category-list clearfix"]/li/div/a/@href') data_url_list = [] for new_url in tree_list: # 获取详情页url new_url = "https://www.pearvideo.com/" + new_url # 向详情页发送请求获取源码数据 detail_text = requests.get(url=new_url,headers=headers).text # 通过正则湖区视频下载url data_list = re.findall(ex,detail_text,re.S) if len(data_list)>0: data_url_list.append(data_list[0]) if not os.path.exists("./video"): os.mkdir("./video") for data_url in data_url_list: filename = "video/" + data_url.split("/")[-1] print(filename) with open(filename,"wb") as f: response = requests.get(url=data_url,headers=headers) f.write(response.content)