导图社区 爬虫、SE
爬虫思维导图,内容分为数据解析、scrapy框架、ip代理、cookie用户状态记录、import requests库、os模块-创建文件夹、异步爬虫、ajas动态数据处理等。
编辑于2022-12-22 20:14:47 广东爬虫
数据解析
re正则表达式
可以结合使用,如\d{n}
re 解析
obj=re.compile("(?P<匹配具体内容>.*?)",re.S)
re.S表示 .也可以匹配空格
预创建正则表达式
res=obj.finditer(x) for i in res:
参数x为字符串
obj=re.compile(r"<div class='.*?><span id='(?p<id>.*?)"</a>,re.S)
(?p<随意名字>正则)这样就可以单独从正则匹配的内容中其提取到需要的名字
re.findall("\d","字符串")
匹配字符串中所有符合正则表达的内容,list形式返回
“/d”代表正则表达式
“字符串”代表request.get().text获取的页面信息
re.findtier("\d","字符串")
因为是迭代器,需要通过for * in *:获取
以迭代器的形式返回结果,使用group()显示内容
效率比findall高
re.search("\d","字符串")
返回第一个匹配到的字符后结束,使用group()显示内容
re.match("\d","字符串")
匹配的字符前不能有其它内容,否则报错,使用group()显示内容
预加载正则表达式
obj=re.compile(r"\d+")
示例:<div class="c-color-text toast">辅助模式</div>
obj=re.compile(r"<div class="c-color-text toast">(?P<名字>.*?)</div>"
(?P)标识要提取的部分 (<>)起一个名字,用group参数的查询 (.*?)可以是\d....,用于提取需要的内容
惰性和贪婪匹配
.* 贪婪匹配
把所有符合要求的提取
.*? 惰性匹配
把第一个符合要求的提取
xpath
选择已知节点
选取未知节点
from lxml import etree
etree.parse(a.html)
接收一个本地文档
url=地址 page_text=request.get(url) tree=etree.HTML(page_text)
接收一个由服务器返回的html数据
tree.xpath('数据解析')「0」
提取列表中的第一个元素
for i in a:
a代表tree.xpath()分析出的标签进行迭代
getall() &extract()方法
tree.xpath().getall()
返回一个list列表,提取不到数据返回一个None,并在同一行中显示
tree.xpath().extract()
返回一个与网页源码相同的界面信息,提取不到数据报错
使用这两个方法可以将Selector对象转换成列字符串
范围选取position()
语法://div[position()<=2]
CSS选择器
find.element(By.CSS_SELECTOR," ")
参数可以是标签名、id、name、class
通过class
find.element(By.CSS_SELECTOR," .class名 ")
与find.element(By.CLASS_NAME," ")相同
通过id
find.element(By.CSS_SELECTOR," #id名 ")
常出现属性
其他属性
find.element(By.CSS_SELECTOR,"[herf='·········' ]")
按次序选择子节点
:nth-child( )
:last-child( )
倒数选择
冒号前是范围限制条件
scrapy框架
安装
1.pip install wheel
2.pip install pywin32
3.pip install scrapy
在终端(cmd)输入scrapy检测是否安装成功,有输出则安装成功
创建一个工程
scrapy startproject xxx
xxx代表要创建的工程文件名
在spider子目录中创建一个爬虫文件,在终端输入cd进入到创建的xxx工程文件下;
scrapy genspider spiderName www.xxx.com
www.xxx.com主要是用于控制爬取的url格式,常规使用会在爬虫文件中注释掉
spiderName是要创建的爬虫文件名
scrapy crawl spiderName
执行工程(spiderName是要执行的文件名)
在终端无法执行此操作,取消settings.py文件中的CONCURRENT_REQUESTS = 32注释
需要的终端(cmd)中执行命令
数据解析
通过"爬虫文件,py"的parse方法,执行response.xpath(),返回的是一个selector对象,通过extract()可以将selector对象以列表的形式输出
for (x,y) in zip(list1,list2):
同时遍历多个列表,使用zip转换成元组格式
setting.py配置设定
USER_AGENT
取消注释,添加UA伪装信息
CONCURRENT_REQUESTS
取消注释
LOG_LEVEL
添加代码,参数‘ERROR’
用于在运行报错信息
持久化存储
基于终端指令:
只能将pase方法返回的内容存储在本地文本文件中
在for循环前新建一个空列表,all_list=[]
需要将pase方法解析到的内容,封装到一个列表中,dic={key:解析到的复制变量 }
all_list.append(dic)
return all_list
终端指令:scrapy crawl xxx -o ./路径.csv
基于管道存储:
在爬虫文件中实例化一个items对象
在爬虫文件中导入items.py的FirstsItem类
from firsts.items import FirstItem
在爬虫文件pase方法中实例化一个FirstItem对象
item=FifstItem()
在pase方法数据解析代码下,把解析到的数据存入实例化后的item管道中
item['content']=content item['author']=author
在parse方法中yield item
将item提交给管道(即提交给pipelines.py中)
例子: for (img_name,strage_name) in zip(name_gongsi,name_zhiwei): item=First1Item() #实例化一个对象 #print(img_name+"--"+strage_name) item['img_name']=img_name item['strage_name']=strage_name yield item
在items.py中修改要存储的信息
取消注释,更改name为存储的变量
name = scrapy.Field()
class First1Item(scrapy.Item): # define the fields for your item here like: img_name = scrapy.Field() strage_name = scrapy.Field()
在pipelines.py中的参数设定
在process_item方法中,先接收item提交过来的爬虫数据
content=item['content'] author=item['author']
重写父类用于打开一个文档和关闭一个文档
def open_spider(self,spider): self.fp=open(./first.txt,'w',encoding='utf-8')
打开文档
在主方法中接受items
def close_spider(self,spider): self.fp.close()
关闭文档
class First1Pipeline: fp=None #重写父类,在数据解释时打开文档(避免每次提交items管道都打开一次文档) #打开文档 def open_spider(self,spider): self.fp=open('./zhaopin.txt','w',encoding='utf-8') def process_item(self, item, spider): img_name=item['img_name'] trage_name=item['strage_name'] self.fp.write(img_name+'***'+trage_name+'\n') return item #关闭文档 def close_spider(self,spider): self.fp.close()
存入数据库MYSQL
新建一个class类用于数据库管道存储
在配置文件中开启管道
在settings.py中ITEM_PIPELINES = { 'first.pipelines.FirstPipeline': 300, }取消注释
递归函数
在函数内部调用函数本身
yield scrapy.request(url=url,callback=self.paser,meta={'item' : item})
callback用于回调函数
meta用于请求传参
请求传参
爬取的信息不在同一张页面上时
因为爬取的数据不在同一张页面当中,所以需要在parse方法中解解释出对应的网页地址
新建一个def方法(例;parse_datail)
这个方法进行另一页面的数据解析
在该方法下进行传参
item=response.meta['item']
接收由主函数回调来的item数据
图片数据爬取
子主题
子主题
子主题
ip代理
在requests请求中,添加参数proxies={"https":"ip地址"}
作用是避免本机ip地址发送频繁被封
cookie用户状态记录
正常requests无法正常进入,需要携带前面的cookie状态参数
使用方法与requests一样,使用session.get/post()请求可以直接得到一个cookie的对象, 手动可以在headers中加入参数,使用session则不用
使用session会话对象进行自动捕捉在登陆时的cookie状态数据,并保存在session对象中
import requests 库
get 获取网页源码
import requests url="网址" res=requests.get(ur,params=dict,headers=dict,verify=False)
params参数携带的是url查找字典 kw=input("输入搜索名字") dic={ 'request':kw } 与post请求的data同理
url
发送请求网址
params
用于网址拼接
headers
UA标签
verify
跳过安全验证(默认True)
post 获取网页源码
import requests url="网址" res=requests.post(url,data=dic,headers=headers)
url
data
headers
三个post参数
r=open('/.文件名.json','w',encoding='utf-8') data=json.dumps('res',fp=r)转完字符串
主要用于ajax动态加载数据
json=data直接把data赋值给json参数也行
files参数上传文件
files={"files":open("文件名.txt","rb")}
主要用于携带参数登陆
除url外,所有参数均使用dict格式编辑
os模块-创建文件夹
os.path.exists(path)
判断path对象是否存在
使用if not os.path.exists(path)
os.mkdir(path)
创建指定目录
os.rmdir(path)
删除指定目录
for 循环不用进行缩进
解决中文显示乱码的方法
在request后直接指定
res.encoding="utf-8"
在request后自动判断类型
res.encoding=res.apparent_encoding
通过解码方式
img_name=res.text.encode('iso-8859-1').decode('gbk')
异步爬虫
单线程+异步爬虫
import asyncio
多线程、多进程(太多会影响本地系统的ccpu资源占用)
线程池(池有上限)
适量使用,主要用在最后请求时
导入线程池模块from multiprocessing.dummy import Pool
""" #实例化一个Pool对象 pool=Pool(5) #5代表的是在池中开展多少个线程 pool.map('传入一个def的方法','可迭代对象-URL') """
需要创建def函数,如果函数没有返回值,则Pool.map()不用赋值变量
ajas动态数据处理
import json模块
在抓包工具中,需要在response取数据,则要用json模块
进行requests.get()请求后,text改用json()拿到XHR中的"preview"中的信息
动态加载的信息大部分不会直接在源码中看到,需要使用"Newwork"抓包工具进行捕获
headers伪装除UA外,部分网站还需要'Referer'参数
import requests from lxml import etree import re import json if __name__=='__main__': url='https://www.pearvideo.com/category_5' lishipin=requests.get(url=url).text tree=etree.HTML(lishipin) list_li=tree.xpath('//ul[@class="listvideo-list clearfix"]/li') a=[] #详情页面的网址 for li in list_li: da_url='https://www.pearvideo.com/'+li.xpath('./div/a/@href')[0] name=li.xpath('./div/a/div[2]/text()')[0]+'.mp4' a.append(da_url) for item in a: url_name=item.replace("https://www.pearvideo.com/video_","") turl="https://www.pearvideo.com/videoStatus.jsp?contId=%s" % url_name #Referer服务器识别来源 headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36', 'Referer':'https://www.pearvideo.com/video_%s' % url_name } #html拿到目标地址的preview的信息 html=requests.get(url=turl,headers=headers).json() #切片出字典信息中的网址位置 srcurl=html['videoInfo']['videos']['srcUrl'] #拼接出需要网址的一部分 cont='cont-'+url_name #404地址的分割 e=srcurl.split('-')[0].split('/')[-1] new_url=srcurl.replace(e,cont) print(new_url)
这是2021-9-27梨视频下载网址的爬虫代码
下载文件
video=request.get('请求下载的网址') with open('文件名',mode='wb') as f: f.write(video.content)
content用于获取二进制内容(如图片,视频),json获取ISON格式数据,text获取字符串
获取网页源码(python自带)
from urllib.request import urlopen url="https://gis-wms.cainiao.com/page/cabinetBatch" a=urlopen(url) print(a.read().decode('utf-8'))
selenium模块
pip install selenium
更便捷的获取网站动态加载的数据
更便捷的进行模拟登陆操作
下载对应浏览器的驱动程序; 下载的驱动程序与浏览器版本要相同
http://npm.taobao.org/mirrors/chromedriver/ http://chromedriver.storage.googleapis.com/index.html
from selenium import webdriver
bro=webdirver.Chrome(′传入一个浏览器驱动′)-实例化一个浏览器对象
bro.get(url)-对一个指定url发起请求
page_text=bro.page_source-使用page_source获取网页源码
定位方式
By.id
By.name
By.link_text
超链接,By.LINK_TEXT,"文本"
By.partial_link_text
超链接,近似
By.Xapth
By.CSS_selector
css选择器
By.tag_name
标签名
web.find_element(By.css_selector," ")
frame切换
选中框
web.swith_to.frame(id&name)
参数必须是id属性或者name属性
返回主框架
web.swith_to.default_content()
获取句柄
获取当前所有网页句柄
handles=web.window_handles
切换到最新打开的窗口
web.switch_to.window(handles[1])
切换到倒数第二个窗口
web.switch_to.window(handles[-2])
切换到最开始打开的窗口
web.switch_to.window(handles[0])
保存当前页面句柄
web1=web.current_window_handle
用于窗口跳转
循环+判断进行窗口切换
切片形式进行切换
选择框
radio
单选
web.find_element(By.CSS_SELECTOR,' '
checkbox
多选
select
下拉选择
from selenium.webdriver.support.ui import Select
创建Select对象
select=Select(web.find_element(By.ID,' '))
通过select进行相关操作
select.deslect_all()清除所有选择
下拉菜单选择定位
sl=select.(web.find_element(By.NAME,"name属性"))
sl.select_by_value("值") sl.select_by_visible_text("文本") sl.select_by_index("序列号")
三种选择方式
弹窗
alart(只有确定)
confirm(有确定有取消)
prompt(有确定有取消还可以输入值)
捕捉不同弹窗 al=web.swith_to.alart
处理弹窗
点击确定al.accept()
输出弹窗文本al.text()
点击取消al.dismiss()
输入值al.send_keys()
智能等待
web.implicitly_wait(5)
每隔0.5秒进行查询一次,5秒内完成
冻结界面
在开发者工具栏Console执行js代码:setTimeout(function(){debugger},5000)