张德长

导航

Python爬虫(学习笔记)

Python爬虫(学习笔记)

 

 

常见的反爬机制及应对策略

名称

描述

解决方案/反反爬措施

1.Headers

 

从用户的headers进行反爬是最常见的反爬策略,Headers是一种最常见的反爬机制Headers是一种区分浏览器行为和机器行为中最简单的方法,还有一些网站会对Referer (上级链接)进行检测 从而实现爬虫。

相应的解决措施:通过审查元素或者开发者工具获取相应的headers 然后把相应的headers 传输给python 的requests,这样就能很好地绕过。

2.IP 限制

 

 一些网站会根据你的IP 地址访问的频率,次数进行反爬。也就是说如果你用单一的IP 地址访问频率过高,那么服务器会在短时间内禁止这个IP 访问。

解决措施:构造自己的IP 代理池,然后每次访问时随机选择代理(但一些IP 地址不是非常稳定,需要经常检查更新)。

3. UA 限制

 

UA 是用户访问网站时候的浏览器标识,其反爬机制与ip 限制类似。

 解决措施:构造自己的UA 池,每次python 做requests 访问时随机挂上UA 标识,更好地模拟浏览器行为。当然如果反爬对时间还有限制的话,可以在requests 设置timeout(最好是随机休眠,这样会更安全稳定,time.sleep())。

 

4.验证码反爬虫或者模拟登陆  

 

验证码:这个办法也是相当古老并且相当的有效果,如果一个爬虫要解释一个验证码中的内容,这在以前通过简单的图像识别是可以完成的,但是就现在来讲,验证码的干扰线,噪点都很多,甚至还出现了人类都难以认识的验证码

解决措施:验证码识别的基本方法:截图,二值化、中值滤波去噪、分割、紧缩重排(让高矮统一)、字库特征匹配识别。(python 的PIL 库或者其他)模拟登陆(例如知乎等):用好python requests 中的session

5.Ajax 动态加载  

 

网页的不希望被爬虫拿到的数据使用Ajax 动态加载,这样就为爬虫造成了绝大的麻烦,如果一个爬虫不具备js 引擎,或者具备js 引擎,但是没有处理js 返回的方案,或者是具备了js 引擎,但是没办法让站点显示启用脚本设置。基于这些情况,ajax 动态加载反制爬虫还是相当有效的。

Ajax 动态加载的工作原理是:从网页的url 加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载出更多的内容,并把这些内容传输到网页中。

 

解决策略:若使用审查元素分析”请求“对应的链接(方法:右键→审查元素→Network→清空,点

 

击”加载更多“,出现对应的GET 链接寻找Type 为text/html 的,点击,查看get 参数或者复制Request

URL),循环过程。如果“请求”之前有页面,依据上一步的网址进行分析推导第1 页。以此类推,抓取Ajax 地址的数据。对返回的json 使用requests 中的json 进行解析,使用eval()转成字典处理fiddler 可以格式化输出json 数据。

 

6.cookie 限制

 

一次打开网页会生成一个随机cookie,如果再次打开网页这个cookie 不存在,那么再次设置,第三次打开仍然不存在,这就非常有可能是爬虫在工作了。

解决措施:在headers 挂上相应的cookie 或者根据其方法进行构造(例如从中选取几个字母进行构造)。如果过于复杂,可以考虑使用selenium 模块(可以完全模拟浏览器行为)

代理IP:一种反反爬机制

作用

突破封IP的反爬机制

什么是代理

代理服务器

先将请求发送至代理服务器,再由代理服务器发送至目标服务器

代理的作用

突破自身IP的访问限制

隐藏真实IP

代理相关网站

www.goubanjia.com

快代理

西祠代理

代理IP的种类

http:适用于http协议的URL访问中

https:应用到https协议的URL访问中

代理IP的匿名度

透明:服务器直到该次请求使用了代理,也知道请求对应的真实IP

匿名:知道使用了代理,但是不知道真实的IP

高匿名:不知道使用了代理,也不知道真实IP

模拟登录session

模拟登录

爬取基于某些用户的用户信息

没有请求到数据的原因

发起的第二次基于个人主页的页面请求的时候,服务器端并不知道该次请求是基于登录状态下的请求;

http、https协议特性

无状态

cookie

用来让服务器端记录客户端的相关状态

手动处理

通过抓包工具F12,获取cookie值,将该值手动粘贴到代码中,封装到headers数据中

自动处理

 

cookie值来源于哪里?

模拟登录post请求后,由服务端创建;

session会话的作用

1可以进行请求的发送;

2如果请求过程中产生了cookie,则该cookie会被自动存储/携带在该session对象中

session实例化

创建一个session对象,session=requests.Session()

使用session对象进行模拟登录post请求的发送(服务端生成的cookie就会存储在session中);

session对象对个人主页对应的get请求进行发送(session携带了cookie)

使用

session.post()

session.get()

 

 

 

通过xpath下载简历模板

import os.path

 

#导入包

from lxml import etree

import requests

#定义函数-爬取单个页面

def OnePage( page_number=1):

    #根据页数生成对应的URL

    url=''

    if page_number==1:

        url = 'https://sc.chinaz.com/jianli/free.html'

    elif(page_number in range(2,1192)):

 

        url='https://sc.chinaz.com/jianli/free_'+str(page_number)+'.html'

 

    #UA伪装

    headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0'}

    #请求整页数据

    #page_text=requests.get(url=url,headers=headers).text

    response=requests.get(url=url,headers=headers)

    #处理中文乱码问题

    response.encoding='utf-8'

    page_text=response.text

    #初始化etree对象

    tree=etree.HTML(page_text)

    #解析对象列表

    page_list=tree.xpath('//div[@class="sc_warp  mt20"]/div/div/div/a')

    #创建文件夹存储下载数据

    folder='./jianli/'

    if not os.path.exists(folder):

        os.mkdir(folder)

        #遍历对象列表

    for page in page_list:

        #解析文件名

        name=page.xpath('./img/@alt')[0]

        #解决中文乱码问题

        #name=name.encode('iso-8859-1').decode('gbk')

        #解析下载页的URL

        href=page.xpath('./@href')[0]

        #print(name,href)

        #处理URL

        if href[0] == "/":

            href = 'https:' + href

        #获取下载页源码

        page_text2=requests.get(url=href,headers=headers).text

        #构造etree对象

        tree2=etree.HTML(page_text2)

        #解析下载地址

        href2=tree2.xpath('//div[@class="down_wrap"]/div[2]/ul/li[1]/a/@href')[0]

        #处理URL

        if href2[0]=="/":

            href2='https:'+href2

        #print(name,href2)

        #添加后缀名

        name=name+'.rar'

        #创建文件路径

        path=folder+name

        #读取文件数据

        data=requests.get(url=href2,headers=headers).content

        #数据持久化

        with open(path,'wb') as fp:

            fp.write(data)

        print(name,'下载成功!!!')

 

#对不同的页码循环执行

for i in range(50,879):

    print(f'开始下载第【{i}】页...')

    try:

        OnePage(i)

    except:

        continue

通过xpath解析,获取网页图片

import os.path

#导入包

import requests

from lxml import etree

#指定URL

url='https://pic.netbian.com/4kmeinv/'

#UA伪装

headers= {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0'}

#读取整页文本

page_text=requests.get(url=url,headers=headers).text

 

#解决中文乱码问题-方法2

#response=requests.get(url=url,headers=headers)

#response.encoding='utf-8'

#page_text=response.text

#初始化etree对象

tree=etree.HTML(page_text)

#解析获取所有对象列表

li_list=tree.xpath('//div[@class="slist"]//li')

folder='./4kMeinv'

if not os.path.exists(folder):

    os.mkdir(folder)

#遍历对象列表

for li in li_list:

    #从对象解析出图片URL,并补全为完整URL

    src='https://pic.netbian.com'+li.xpath('./a/img/@src')[0]

    #读取图片二进制数据

    data=requests.get(url=src,headers=headers).content

    #获取文件名称

    name=li.xpath('./a/img/@alt')[0]+'.jpg'

    #解决中文乱码问题-方法1

    name=name.encode('iso-8859-1').decode('gbk')

    #print

    path=folder+'/'+name

    #数据持久化存储

    with open(path,'wb') as fp:

        fp.write(data)

        print(name,',    保存成功!!!')

 

 

导入包

 

指定URL

UA伪装

 

读取整页文本

 

 

 

 

etree初始化

xpath解析

 

 

 

 

 

 

 

xpath二次解析

获取图片URL

下载图片数据(二进制)

获取文件名称

 

 

 

 

 

数据持久化

HTML常用标签及其全称

HTML标签

英文全称

中文释义

a

Anchor

abbr

Abbreviation

缩写词

acronym

Acronym

取首字母的缩写词

address    

Address

地址

dfn           

Defines a Definition Term

定义定义条目

kbd          

Keyboard

键盘(文本)

samp      

Sample

示例(文本

var            

Variable

变量(文本)

tt               

Teletype

打印机(文本)

code

Code

源代码(文本)

pre

Preformatted

预定义格式(文本 )

blockquote    

Block Quotation

区块引用语

cite          

Citation

引用

q

Quotation

引用语

strong

Strong

加重(文本)

em          

Emphasized

加重(文本)

b

Bold

粗体(文本)

i

Italic

斜体(文本)

big          

Big

变大(文本)

small      

Small

变小(文本)

sup          

Superscripted

上标(文本)

sub          

Subscripted

下标(文本)

bdo          

Direction of Text Display

文本显示方向

br            

Break

换行

center    

Centered

居中(文本)

font          

Font

字体

u              

Underlined

下划线(文本)

s/ strike      

Strikethrough

删除线

div              

Division

分隔

span          

Span

范围

ol                

Ordered List

排序列表

ul               

Unordered List

不排序列表

li

List Item

列表项目

dl                

Definition List

定义列表

dt                 

Definition Term

定义术语

dd             

Definition Description

定义描述

del               

Deleted

删除(的文本)

ins               

Inserted

插入(的文本)

h1~h6

Header 1 to Header 6

标题1到标题6

p

Paragraph

段落

hr                

Horizontal Rule

水平尺

href

hypertext reference

超文本引用

alt

alter

替用(一般是图片显示不出的提示)

src

Source

源文件链接

cell

cell

cellpadding

cellpadding

巢补白

cellspacing

cellspacing

巢空间

nl

navigation lists

导航列表

tr

table row

表格中的一行

th

table header cell

表格中的表头

td

table data cell

表格中的一个单元格

iframe

Inline frame

定义内联框架

optgroup

Option group

定义选项组

通过etree-xpath获取二手房源标题

from lxml import etree

import requests

#指定URL

url='https://nc.58.com/ershoufang/'

#UA伪装

headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0'}

#获取整页文本

page_text=requests.get(url=url,headers=headers).text

#初始化etree对象

tree=etree.HTML(page_text)

#第一次解析,获取对象列表

div_list=tree.xpath('//section[@class="list"]/div')

#打开文件

fp=open('./58.txt','w',encoding='utf-8')

#遍历对象列表

for div in div_list:

    #第二次解析,获取二手房源标题

    title=div.xpath('./a/div/div/div/h3/text()')[0]

    #数据持久化,写入本地文件

    fp.write(title+'\n')

    #print(title)

 

 

 

导入包

指定URL

ua伪装

获取页面文本

初始化etree对象

通过xpath表达式

解析获取指定内容

数据持久化存储

 

解析方式总结

名称

正则表达式

BeautifulSoup

xpath

安装

--

pip install bs4

pip install lxml

pip install xpath

pip install lxml

导入包

import re

import requests

from bs4 import BeautifulSoup

import requests

from lxml import etree

import requests

原理

获取整页文本

指定re表达式

通过re方法匹配

获取指定内容

持久化数据存储

实例化soup对象

将页面文本载入soup对象

soup解析获取指定内容

持久化存储数据

1实例化一个etree对象,将需要解析的对象加载到该对象中

2调用etree中的xpaht方法,结合xpath表达式,实现标签定位和内容捕获

初始化

re.findall(ex,text,re.S)

本地数据初始化

soup=BeautifulSoup(fp,'lxml')

网页文本初始化

soup=BeautifulSoup(page_text,'lxml')

将本地文档源码加载到etree对象中

etree.parse(filePath)

将互联网的源码数据加载到etree对象中

etree.HTML(page_text)

方法

requests.get(url,headers)

requests.post(url,param,headers)

response.text文本

response.json

response.content二进制

soup.a/div/p/title/text/string

text返回该标签下所有文本内容(各级子标签)

string只返回本标签下的文本内容

例子:soup.title.parent.name

例子:soup.div.div.div.a.text

soup.find(‘tagName’),soup.find_all()

soup.find(‘tagName’,class_=’属性名’)

soup.select('.bookcont > ul > span > a')

selecet多级访问,返回所有匹配项

.bookcont表示属性名ul表示标签名

find_all()方法没有找到目标是返回空列表,find()方法找不到目标时,返回None

通过CSS的类名查找:soup.select(".sister")

通过tag标签逐层查找:(可跨级)

soup.select("body a")

找到某个tag标签下的直接子标签:

soup.select("head > title")(不可跨级)

soup.a[‘href’]

xpath(‘xpath表达式’)

./表示当前目录

/(最左侧)表示根目录

/(不在最左侧)表示一个层级,相当于bs4的>

//(最左侧)表示多个层级相当于bs4的空格

//(不在最左侧)表示从任意层级开始定位

属性定位://tag[@attrName=’attrVal’]

索引定位:索引下标从1开始而不是从0开始,tag[@attrName=’attrVal’]/p[3]

‘//div[@class=’tang’]//li[5]/a/text()’[0]

/text()本层级内容

//text()所有层级内容

/@attrName取属性值

其他

中文文档

https://docs.python.org/zh-cn/3/library/index.html

中文文档

https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#find

中文文档

https://www.w3cschool.cn/lxml/

通过bs4解析三国

from bs4 import BeautifulSoup

import lxml

import requests

url='https://so.gushiwen.cn/guwen/book_46653FD803893E4F7F702BCF1F7CCE17.aspx'

headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0'}

page_text=requests.get(url=url,headers=headers).text

soup=BeautifulSoup(page_text,'lxml')

#print(soup.div.div.div.a.text)#古诗文网

#print(soup.div.div.string)#None

#print(soup.div.div.div.a['href'])

chapters=soup.select('.bookcont > ul > span > a')

print(chapters)

with open('sanguo.txt','w',encoding='utf-8') as fp:

    for a in chapters:

        title=a.string

        link=a['href']

        page_content=requests.get(url=link,headers=headers).text

        soup2=BeautifulSoup(page_content,'lxml')

        content=soup2.find('div',class_='contson')

        content_text=content.text

        fp.write(title+':\n'+content_text+'\n')

        print(title ,' 写入成功!!!')

 

导入

指定URL

UA伪装

 

读取起始页

 

创建soup对象,解析标题和内容URL

读取章节内容

 

 

 

 

 

 

 

 

 

 

 

创建soup2,解析章节内容

数据持久化,写入本地TXT文件

正则解析--爬取网页中的美女图片

import os.path

import requests

import re #导入包

#UA伪装

headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0'}

#存储图片的文件夹

folder='./meinv/'

if not os.path.exists(folder):

    os.mkdir(folder)

#指定URL

url='https://m.woyaogexing.com/tupian/z/meinv/'

#解析正则表达式

ex='" data-src="(.*?)" />'

#src="//img.woyaogexing.com/images/grey.gif" data-src="//img2.woyaogexing.com/2022/07/03/ecb599c9ffa42f2f!400x400.jpg" />

#解析获取图片url列表

text=requests.get(url=url,headers=headers).text

image_list=re.findall(ex,text,re.S)

 

print(image_list)

#遍历图片URL

for src in image_list:

    src='https:'+src #生成完整路径

    img_data=requests.get(url=src,headers=headers).content #读取图片的二进制数据content

    name=src.split('/')[-1] #从路径获取图片名称

    path=folder+name #写入文件路径

    with open(path,'wb') as fp:#打开文件

        fp.write(img_data) #写入数据

        print(name,'保存成功')#打印日志

n 导入包

n UA伪装

n 创建文件夹存储图片

 

n 指定URL

n 读取页面所有内容

 

 

n 根据页面格式,编制正则表达式

n 通过正则表达式,解析页面内容获取图片url

 

 

n 遍历所有图片url

n 读取图片二进制数据

 

n 图片数据持久化存储

 

 

聚焦爬虫,爬取页面中指定的页面内容,例如豆瓣中评分>9的电影;

数据解析:从整个页面中获取所需的部分信息;

数据解析分类:

  • 正则
  • bs4-beautiful Soup
  • xpath-通用性强

数据解析原理:

解析的局部的文本内容都会在标签之间或者标签对应的属性中进行存储;

1 进行指定标签的定位

2 标签或者标签对应的属性中存储的数据值进行提取(解析)

爬取肯德基餐厅数据

import json#导入包

import  requests

#指定URL

url='http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'

add='南昌'#指定参数

params={

'cname': '',

'pid': '',

'keyword': add,

'pageIndex': 1,

'pageSize': 10,

}#UA伪装

headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0'}

#发起请求

response=requests.post(url=url,headers=headers,params=params)

json_obj=response.json()#获取数据

print(json_obj)

with open('kfc_'+add+'.json','w') as fp:

    json.dump(json_obj,fp=fp)

#数据持久化保存

print('成功保存')

requests爬虫流程

 

1导入包

 

2 指定url(通过F12调试查看)

 

3指定参数(通过F12调试查看)

 

4指定UA(UA伪装)

 

5发起请求get/post

 

6获取数据

 

7数据持久化保存

 

posted on 2022-10-19 09:29  张德长  阅读(355)  评论(0编辑  收藏  举报