python知识-爬虫
1.requests
使用requests请求数据的流程
(1)请求网络数据,requests.get(“请求地址”)
(2)设置解码方式(乱码时设置,在获取结果之前设置)
(3)获取请求结果
- (1)获取请求结果对应的文本数据-爬网页(网页源代码)
- (2)获取二进制格式的请求结果-下载图片,视频,音频的时候使用
- (3)获取请求内容json转换的结果-json接口数据
# 1 请求网络数据,requests.get("请求地址")
res = requests.get("https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js")# 2.设置解码方式(乱码时设置,在获取结果之前设置)
# meta->charset
# res.encoding=''# 3.获取请求结果
# (1)获取请求结果对应的文本数据-爬网页(网页源代码)
# print(res.text)
# (2)获取二进制格式的请求结果-下载图片,视频,音频的时候使用
# print(res.content)
# (3)获取请求内容json转换的结果-json接口数据
2.反爬处理
反爬是浏览器为减少被爬取的次数。其实就是网站为了维护自己的核心安全而采取的抑制爬虫的手段和措施。
常见的反爬策略:
- 浏览器伪装(user-aget)
- 免密登录(cookie)
- 设置代理(proxies)
3.os模块
python提供的系统模块,提供python处理文件和文件夹的操作(注不是操作文件和文件夹内容,而且对文件和文件夹本身操作)
(1)os.mkdir(文件路径)——在指定路径创建指定文件夹,若文件已经存在,那么会报错
(2)os.path.exists(文件夹路径/文件路径)——判断文件或者文件夹是否存在
4.正则表达式
(1)正则表达式的作用
正则表达式是一种可以让复杂的字符串变得简单工具,写正则表达式的时候就是用正则符号描述字符串的规则。
(2)re模块——提供python中所有的正则相关的函数
常见的正则函数:
- fullmatch(正则表达式,字符串)——判断指定字符串是否满足正则表达式描述的规则
- findall(正则表达式,字符串)——提取字符串中所有满足正则表达式的字符串
- search(正则表达式,字符串)——匹配字符串中第一个满足正则表达式的字符串
注意:python中表达式一个正则表达式一般使用r字符串
(3)正则的语法
1)普通符号——在正则表达式中表示符号本身的符号
2)特殊符号
+++++++++++++++++++++匹配类符号+++++++++++++++++++++++++++++
-
.——匹配任意一个字符
res=re.fullmatch(r'.bc','*bc')#任意符号 #表示字符串的第一位可以是任意包括但不限于字符,中文,符号等
-
\d——匹配任意一个数字
res=re.fullmatch(r'\d\dabc','68abc')#表示字符串前两个为数字
-
\s——匹配任意一个空白字符(空格,换行,水平制表符)
res=fullmatch(r'123\sabc','123 abc') #匹配123 abc或者123\tabc或者123\nabc,注意水平制表符要用\t,如果手动按tab则是四个字符
-
\w ——匹配任意一个字母,数字,下划线或者中文
res=fullmatch(r'abc\w123','abc和123') #abc和123之间可以是字母数字下划线和中文都行
-
\D、\S、\W——分别和\d,\s,\w的功能相反
res=fullmatch(r'123\Dabc','123dabc') #只要123和abc之间不是数字都可以,如果是数字那么会出错,\S,\W也是如此
-
[字符集]——匹配在字符集中的任意一个字符
res=fullmatch(r'abc[M9你]','abc9123') #符合表达式的就三种情况'abc9123','abcM123','abc你123' #res.fullmatch(r'abc[\d]','abc0'),表示abc后可以是一个数字 #[1-5]-匹配字符1到字符5中的任意一个字符 #[a-z]-匹配任意一个小写字母 #[A-Z]匹配任意一个大写字母 #[a-zA-Z]-匹配任意一个字母 #[a-zA-Z\d]-匹配任意一个字母或者数字 #[a-z=%]-匹配任意一个小写字母、或者 = 或者 % #[\u4e00-\u9fa5]-匹配任意一个中文
-
[^字符集]-匹配不在字符集中的任意一个字符
res=fullmatch(r'abc[^MN]123','abcl123') #abc和123之间只要不是MN都可以 #注意^只有放在最开头才可以,放在中间只代表普通字符
++++++++++++++++++匹配次数符号++++++++++++++++++
匹配类符号匹次数(即要跟在匹配类符号后面使用,不能单独使用)
-
*-任意次数(0次或者一次或者次数)
a*#——a出现任意多次
\d*-#任意多个数字
res=fullmatch(r'1a*2','12')
#1和2之间可以是0个a,1个a,甚至是多个a
res=fullmatch(r'M\d*N','M2N')
#M和N之间可以是任意个数字
-
+——一次或者多次(至少一次)
res=fullmatch(r'1a+2','1a2') #a至少一次
-
?——0次或者1次
res=fullmatch(r'1a?2','1a2') #a只能是0次或者1次,多了就会报错
-
{}
- {N}-N次
- {M,N}-M到N次
- {M,}-至少M次
- {,N}-最多N次
res=fullmatch(r'1a{3}2','1aaa2')
#a出现三次
#匹配任意一个除了0的整数(第一位不是0)
res=re.fullmatch(r'[+-]?[1-9]\d*','-555')
print(res)
检测类符号:是在匹配成功的时候检测所在的位置是否符合要求
-
\b——检测是否是单词边界(任何时候可以将不同的单词进行区分的符号:空白字符,标点符号,字符串开头,字符串结尾)
msg = '238jshs90睡 觉睡觉2838,换手89 , 100还是说78世界上78,628. 829=sjs好几家899' result = fingqjall(r'\d+\b', msg)#匹配的时候并不是数字就行,要求数字后面是字符边界才行(字符)-即以字符尾随的数字 print (result)
-
^检测是否是字符串开头
-
$检测是否是字符串结尾
5.贪婪和非贪婪模式
在匹配次数不确定的时候,如果有多种次数都可以匹配成功,贪婪取最多的那个次数,非贪婪取最少的那个次数
贪婪模式:+,?,*,{M,N},{M,},{,N}
非贪婪模式:+?,??,*?,{M,N}?,{M,}?,{,N}?
#贪婪算法-其中有多个a,贪婪取到最后的a
res=re.search(r'a.+a','阿斯顿addasdfasdf24')
print(res)
#<re.Match object; span=(3, 11), match='addasdfa'>#非贪婪算法-非贪婪取到第二个a
res=re.search(r'a.+?a','阿斯顿addasdfasdf24')
print(res)
#<re.Match object; span=(3, 7), match='adda'>
# 练习:使用正则表达式提取top250一页每个电影的详情页地址
import re
import requestsurl = 'https://movie.douban.com/top250?start=0&filter='headers = {"user-agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54'
}
res = requests.get(url, headers=headers)
result = res.text
respoense = re.findall(r'<a href="(.+?)" class="">', result)
print(respoense,len(respoense))#练习2:使用正则表达式提取top250每个电影的详情页地址import re
import requestslist1=[]
#经过对比发现下一页比上一次多25,总的250,但开始为0的时候有一页,最后一页为225
for i in range(0,226,25):url = f'https://movie.douban.com/top250?start={i}&filter='headers = {"user-agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54'}res = requests.get(url, headers=headers)result = res.text# print(result)list1+=re.findall(r'<a href="(.+?)" class="">', result)# print(response,sep="\n")
print(list1,len(list1))
6.分组和分支
(1)分组-()
正则表达式中可以用()将部分内容括起来表示一个整体;括起来的的部分就是一个分组,以下几种情况需要用到分组:把某部分当作整体,重复某部分,提取分组中的内容
-
整体操作的时候需要分组
'23M','89K10L','09H56P66U' result=fullmatch(r'(\d\d[A-Z])+','09H56P66U') print(result) #经过对比发现前两个都是数字后面一个是大写字母,将三个为一组
-
重复匹配-正则可以通过\M可以 重复它前面第M个分组匹配的结果
result=fullmatch(r'(\d\d)[A-Z]\1','90K90')
print(result)
#经过对比发现需要匹配的数据前后数字相同,即某个地方相同,可以用\1来匹配第一个括号括起来的分组(\d\d),它匹配的额结果是两个数字,即重复两个数字result=fullmatch(r'(\d{3})([a-z])=\2\1{2}','234km=km234234')
print(result)
#result所表达的规则是:匹配开个三个数字后面是两个小写字母,等号后面重复第二个分组一次和第一个分组两次
-
捕获-提取分组匹配到的结果(捕获分为自动捕获(只有findall有)和手动捕获两种)-即单独将分组(括号)中的内容提取出来
-
findall在正则表达式中有分组的时候,会自动提取正则匹配结果中分组匹配到的内容
-
手动捕获
import re message = ' 我是小明,今年23岁,身高180厘米,体重70kg ' result = re.search(r'身高(\d+)厘米,体重(\d+)kg', message) print(result) # 是一个匹配对象 # <re.Match object; span=(11, 16), print(result.group()) # 将匹配对象中指定分组匹配到的内容 # '身高180' print(result.group(1)) # 匹配第一个分组的值 # '180'
-
(2)分支-—— |
正则1|正则2|正则3… ————先用正则1进行匹配,匹配成功就直接成功;匹配失败用正则2 进行匹配…;相当于或者
result=fullmatch(r'abc\d\d|abc[A-Z]{2}','abcLS')
print(result)result=fullmatch(r'abc(\d\d|[A-Z]{2})','abc12')
print(result)
====转义符号
转义符号:在本身具有特殊功能或者特殊意义的符号前加 \,让特殊符号编程普通字符
result=fullmatch(r'\([a-z]{3}\)','(jkl)')
print(result)
注意:单独存在有特殊意义的符号,在[ ]中他们的功能会自动消失
result=fullmatch(r'\d[+.?*()\]]\d','3+4')
print(result)
7.re模块
-
fullmatch(正则表达式,字符串)——用整个字符串和正则,匹配成功返回匹配对象,匹配失败返回None
-
search(正则表达式,字符串)——匹配第一个满足正则的表达式,匹配成功返回匹配对象,匹配失败返回None
-
findall(正则表达式,字符串)——获取字符串中所有满足正则的的字串,默认返回一个列表,列表中的元素是所有匹配到的字串(存在自动捕获对象-分组对象)
-
split(正则表达式,字符串,N)——将字符串中所有满足正则的字串作为切割点进行切割
import re str1='技术和还是5阿萨大大882阿斯顿' print(re.split(r'\d+',str1))
-
sub(正则表达式,字符串1,字符串2)——将字符串2中所有满足正则的字串都替换成字符串1
import re message='妈的,sb,都打起来了还在打野!草' print(re.sub(r'(?i)妈的|sb|操|草|艹|fuck|f\s*u\s*c\s*k','*',message))
-
finditer(正则表达式,字符串)——获取字符串中所有满足正则的子串,返回一个迭代器,迭代器中的元素是匹配对象
-
match(正则表达式,字符串)——匹配字符串开头
(1)忽略大小写
(?i)在正则前面加,表示忽略大小写
# 1)忽略大小写: (?i)
print(fulLmatch(r'(?i)abc','abc'))
print(fulLmatch(r'(?i)abc',' Abc'))
print(fulLmatch(r'(?i)abc','ABc'))
print(fulLmatch(r'(?i)abc','aBc'))
(2)单行匹配(?s)–在匹配规则前
多行匹配(默认):. 不能和换行符进行匹配
单行匹配:. 可以和换行符进行匹配
8 .selenium
1.selenium创建步骤
from selenium.webdriver import Chrome# 1.创建浏览器对象
b = Chrome()# 2.打开网页(需要爬那个页面的数据,就打开那个页面对应的网页地址)
b.get('https://movie.douban.com/top250?start=0&filter=')# 3.获取网页源代码(注意:不管以什么样的方式更新了界面内容,page_source的内容也会更新)
print(b.page_source) # 获取豆瓣电影top250的网页源代码print('--------------------------------华丽的分割线-------------------------------------')b.get('https://www.baidu.com')print(b.page_source)input('结束:')
2.selenium翻页
(1)找到不同页的地址的变化规律,利用循环实现多页数据的请求
b = Chrome()
for x in range(0, 76, 25):b.get(f'https://movie.douban.com/top250?start={x}&filter=')print(b.page_source)
# print('--------------------------------华丽的分割线-------------------------------------')input()
(2)点击翻页按钮,刷新页面内容,在刷新后获取网页源代码
from selenium.webdriver.common.by import Byb = Chrome()
b.get('https://movie.douban.com/top250?start=0&filter=')for _ in range(5):print(b.page_source)# 点击下一页按钮next = b.find_element(By.CLASS_NAME, 'next')# 点击按钮next.click()
3.翻页按钮涉及到的知识
(1)selenium获取标签
- 1)浏览器对象.b.find_element(获取方式, 数据) - 返回符合条件的第一个标签,结果是标签对象
- 2)浏览器对象.b.find_elements(获取方式, 数据) - 返回符合条件的所有标签,结果是列表,列表中的元素是标签对象
(2)操作标签
- 1)输入框输入内容:输入框对应的标签.send_keys(内容)
- 2)点击标签:标签对象.click()
from selenium.webdriver.common.by import Byb = Chrome()
b.get('https://www.jd.com/')# 获取id属性值为key的标签
search = b.find_element(By.ID, 'key')
search.send_keys('电脑\n')# 获取标签内容为"便宜包邮"的a标签
a1 = b.find_element(By.LINK_TEXT, '便宜包邮')
# a1.click()# 获取标签内容中包含'口好'的a标签
a2 = b.find_element(By.PARTIAL_LINK_TEXT, '口好')
# a2.click()input(':')
#案例:获取知网每个页面中论文的摘要from selenium.webdriver import Chrome
from selenium.webdriver.common.by import By
import time
from bs4 import BeautifulSoupdef analysis_data(html):soup = BeautifulSoup(html, 'lxml')digest = soup.select_one('#ChDivSummary').textprint(digest)def get_net_data():# 1.创建浏览器b = Chrome()# 2.打开中国知网b.get('https://www.cnki.net/')# 3.获取输入框,输入"数据分析"search = b.find_element(By.ID, 'txt_SearchText')search.send_keys('数据分析\n')time.sleep(1)for _ in range(3):# 4.获取搜索结果所有论文的标题标签titles = b.find_elements(By.CLASS_NAME, 'fz14')for x in titles:# 点击一个搜索结果x.click()time.sleep(1)# 切换选项卡,让浏览器对象指向详情页b.switch_to.window(b.window_handles[-1])# 获取详情页数据, 解析数据# print(b.page_source)analysis_data(b.page_source)# 关闭当前窗口b.close()# 将选项卡切换回第一个页面b.switch_to.window(b.window_handles[0])print('--------------------一页数据获取完成--------------------------')b.find_element(By.ID, 'PageNext').click()time.sleep(4)input()if __name__ == '__main__':get_net_data()
4.滚动条
# =====用代码控制浏览器滚动=====
# js中页面鼓动的代码:window.scrollBy(x方向的偏移量, y方向的偏移量)
# b.execute_script('window.scrollBy(0, 8000)')
from selenium.webdriver import Chrome
from selenium.webdriver.common.by import By
import timeb = Chrome()
b.get('https://search.jd.com/Search?keyword=%E7%94%B5%E9%A5%AD%E9%94%85&enc=utf-8&wq=%E7%94%B5%E9%A5%AD%E9%94%85&pvid=058303d3cd58499fb8f5f3459afd4d6b')
time.sleep(2)
for x in range(10):b.execute_script('window.scrollBy(0, 800)')time.sleep(1)time.sleep(2)
result = b.find_elements(By.CSS_SELECTOR, '#J_goodsList>ul>li')
print(len(result))input('结束:')