Python 爬虫主要是为了方便学习新语言和学习资料的爬取
1 了解robots.txt
1.1 基础理解
robots.txt 是一个纯文本文件,在这个文件中网站管理者可以声明该网站中不想被robots访问的部分,或者指定搜索引擎只收录指定的内容,一般域名后加/robots.txt ,就可以获取 当一个搜索机器人(有的叫搜索蜘蛛)访问一个站点时,它会首先检查该站点根目录下是否存在robots.txt ,如果存在,搜索机器人就会按照该文件中的内容来确定访问的范围;如果该文件不存在,那么搜索机器人就沿着链接抓取 另外,robots.txt 必须放置在一个站点的根目录下,而且文件名必须全部小写。 robots.txt 写作语法 首先,我们来看一个robots.txt 范例:https://fanyi.youdao.com/robots.txt 访问以上具体地址,我们可以看到robots.txt 的具体内容如下
User-agent: Mediapartners-Google
Disallow:
User-agent: *
Allow: /fufei
Allow: /rengong
Allow: /web2/index.html
Allow: /about.html
Allow: /fanyiapi
Allow: /openapi
Disallow: /app
Disallow: /?
以上文本表达的意思是允许所有的搜索机器人访问fanyi.youdao.com 站点下的所有文件 具体语法分析:User-agent :后面为搜索机器人的名称,后面如果是* ,则泛指所有的搜索机器人;Disallow :后面为不允许访问的文件目录
1.2 使用robots.txt
robots.txt 自身是一个文本文件。它必须位于域名的根目录中并被命名为robots.txt 。位于子目录中的 robots.txt 文件无效,因为漫游器只在域名的根目录中查找此文件。例如,http://www.example.com/robots.txt 是有效位置,http://www.example.com/mysite/robots.txt 则不是有效位置
2 Cookie
由于http/https 协议特性是无状态特性,因此需要服务器在客户端写入cookie ,可以让服务器知道此请求是在什么样的状态下发生
2.1 两种cookie处理方式
cookie 简言之就是让服务器记录客户端的相关状态信息,有两种方式:
- 手动处理
通过抓包工具获取cookie 值,然后将该值封装到headers中
headers={
'cookie':"...."
}
在发起请求时把cookie封装进去
- 自动处理
自动处理时,要明白cookie 的值来自服务器端,在模拟登陆post 后,服务器端创建并返回给客户端 主要是通过session 会话对象来操作cookie ,session 作用:可以进行请求的发送;如果请求过程中产生了cookie 会自动被存储或携带在该session 对象中 创建session 对象:session=requests.Session() ,使用session 对象进行模拟登陆post 请求发送(cookie 会被存储在session 中) 发送session 请求:session.post() 在发送时session 对象对要请求的页面对应get 请求进行发送(携带了cookie )
3 常用爬虫方法
用python 爬取数据解析原理:
3.1 bs4
3.1.1 基础介绍
bs4 进行网页数据解析 bs4 解析原理:
- 通过实例化一个
BeautifulSoup 对象,并且将页面源码数据加载到该对象中 - 通过调用
BeautifulSoup 对象中相关的属性或者方法进行标签定位和数据提取
环境安装:
pip install bs4
pip install lxml
3.1.2 bs4使用
3.1.2.1 获取解析对象
如何实例化BeautifulSoup 对象: 导包from bs4 import BeautifulSoup 对象的实例化,有两种,本地和远程:
- 将本地的
html 文档中的数据加载到该对象中
fp = open('./test.html','r',encoding='utf-8')
soup=BeautifulSoup(fp,'lxml')
- 将互联网上获取的页面源码加载到该对象中
page_text = response.text
soup=BeautifulSoup(page_text,'lxml')
3.1.2.2 使用bs4解析
使用bs4 提供的用于数据解析的方法和属性:
-
soup.tagName :返回的是文档中第一次出现的tagName 对应的标签,比如soup.a 获取第一次出现的a 标签信息 -
soup.find() : 在使用find('tagName') 效果是等同于soup.tagName ; 进行属性定位,soup.find(‘div’,class_(或id或attr)='song') :示例就是定位带有class='song' 的div 标签,class_ 必须有下划线是为了规避python 关键字 还可以是其他比如:soup.find(‘div’,id='song') :定位id是song的div标签 soup.find(‘div’,attr='song') :定位attr是song的div标签 -
soup.find_all('tagName') :返回符合要求的所有标签(列表)
select 用法:
获取标签之间文本数据 可以使用text 或string 或get_text() ,主要区别:
text 或get_text() 可以获取某一个标签中所有的文本内容string :只可以获取该标签下面直系的文本内容
获取标签中属性值:
- 使用
python 获取字典方法获取,比如:soup.a['href'] 就是获取<a> 中的href 值
3.1.2 使用例子
import os
import requests
from bs4 import BeautifulSoup
headers={
'User-Agent':"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
}
url="https://www.test.com/chaxun/zuozhe/77.html"
def getPoems():
res= requests.get(url=url,headers=headers)
res.encoding='UTF-8'
page_text=res.text
soup = BeautifulSoup(page_text,'lxml')
shici_list = soup.select(".shici_list_main > h3 > a")
shici_name=[]
for li in shici_list:
data_url = "https://www.test.com"+li['href']
shici_name.append(li.string)
detail_res = requests.get(url=data_url,headers=headers)
detail_res.encoding='UTF-8'
detail_page_text=detail_res.text
detail_soup = BeautifulSoup(detail_page_text,'lxml')
detail_content = detail_soup.find("div",class_="item_content").text
with open("./shici.txt",'a+',encoding= 'utf8') as file:
if shici_name.count(li.string)==1:
file.write(li.string)
file.write(detail_content+"\n")
print(li.string+"下载完成!!!!")
if __name__=="__main__":
getPoems()
3.2 xpath
xpath 解析:最常用且最便捷高效的一种解析方式
3.2.1 xpath基础介绍
xpath 解析原理:
- 实例化一个
etree 的对象,且需要将被解析的页面源码数据加载到该对象中 - 调用
etree 对象中的xpath 方法结合着xpath 表达式实现标签的定位和内容的捕获
环境安装:
pip install lxml
3.2.2 xpath使用
3.2.2.1 获取相关对象
先实例化一个etree 对象,先导包:from lxml import etree
- 将本地的
html 文档中的源码数据加载到etree 对象中
tree=etree.parse(filepath)
- 可以将从互联网上获取的源码数据加载到该对象中
page_text = response.text
tree=etree.HTML(page_text)
3.2.2.2 通过xpath解析
通过xpath 表达式:tree.xpath(xpath表达式) : xpath 表达式:
/ :表示的是从根节点开始定位,表示的是一个层级// :表示的是多个层级,可以表示从任意位置开始定位- 属性定位:
tag[@attrName='attrValue'] 比如//div[@class='song'] 表示的是获取到任意位置class='song' 的<div> 标签 - 索引定位:
//div[@class='song']/p[3] 表示的是任意位置class='song' 的<div> 标签下面的第三个<p> 标签,注意: 索引定位是从1 开始的 - 取文本:
/text() :获取的是标签中直系文本内容 //text() :标签中非直系的文本内容(所有的文本内容) - 取属性:
/@attrName :获取某个属性的值,比如://img/@src 获取任意的img 标签的src 值
3.2.3 使用例子
import requests
from lxml import etree
import re
headers={
'User-Agent':"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
}
url="https://www.test.com/chaxun/zuozhe/77.html"
def getPoemsByXpath():
res= requests.get(url=url,headers=headers)
res.encoding='UTF-8'
page_text=res.text
tree = etree.HTML(page_text)
shici_list = tree.xpath("//div[@class='shici_list_main']")
shici_name_out=''
for shici in shici_list:
shici_name=shici.xpath("h3/a/text()")[0]
shici_text_list=shici.xpath("div//text()")
with open("./shicibyxpath.txt",'a+',encoding= 'utf8') as file:
if shici_name_out!=shici_name:
file.write(shici_name+"\n")
for text in shici_text_list:
if "展开全文"==text or "收起"==text or re.match(r'^\s*$',text)!=None or re.match(r'^\n\s*$',text)!=None:
continue
re_text=text.replace(' ','').replace('\n','')
file.write(re_text+"\n")
if shici_name_out!=shici_name:
print(shici_name+"下载完成!!!!")
shici_name_out=shici_name
if __name__=="__main__":
getPoemsByXpath()
|