python爬虫从入门到放弃,含案例分析,超详细讲解
Posted ꧁༺空༒白༻꧂
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python爬虫从入门到放弃,含案例分析,超详细讲解相关的知识,希望对你有一定的参考价值。
Python爬虫
1、认识爬虫
1.1、概述
网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者)
按照一定规律,自动地抓取万维网信息的程序或者脚本。
1.2、应用场景
- 爬取网页优秀的图片信息
- 爬取劲爆视频的弹幕信息
- 爬取优秀的歌声以及曲目
1.3、爬虫和python
爬虫只能用python写吗?其实不然,用Java,c都能写,只不过python对于小白上手快,就像吃饭一般,筷子、勺子、甚至用手抓,他都是可以的,但是大家也都知道筷子勺子吃又优美雅观而且干净。
1.4、爬虫合法吗?
合法!他就像是小刀的存在,小刀可以给人类带来便利,带来一点点危害,也可能会带来很大的危害,没有什么物品是错误的,有的是使用的人,怎么使用,这是关键!
- 善意的爬虫:不破坏网站的资源
- 恶意的爬虫:影响网站的正常运行
1.5、第一个简单的爬虫
from urllib.request import urlopen
url="http://www.baidu.com"#获取网站的地址
resp=urlopen(url)#响应地址打开
with open("baidu.html",mode="w",encoding="utf-8") as f:#open方法,文件输出,mode写操作用法,编码格式encoding
f.write(resp.read().decode("utf-8"))#响应并读写到指定文件
print("over!")
2、web请求过程解析
-
服务器渲染:在服务器那边会把数据和HTML整合到一起,统一返回给浏览器页面中即可看到数据
-
客户端渲染:第一次请求只要一个HTML骨架,第二次请求拿到数据进行数据展示
- 我们在请求页面的时候,第一次的请求往往是只有一个骨架
- 需要二次请求,才能得到其中的数据,这个看我如下操作
3、HTTP协议
3.1、概述
超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议
它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。
请求和响应消息的头以ASCII形式给出;而消息内容则具有一个类似MIME的格式。
3.2、HTTP协议把消息分为三大块内容
- 请求
- 请求行:请求方式(get/post)请求url 协议
- 请求头:放一些服务器要使用的附加信息
- 请求体:一般放一些请求参数
- 响应
- 状态行:协议 状态码
- 响应头:放一些客户端要使用的一些附加信息
- 响应体:服务器返回真正客户端的内容(html,json)
3.3、爬虫常见的重要信息
- 请求头
- User-Agent:请求载体的身份标识(用啥发送的请求)
- Referer:防盗链(这次请求从哪个页面来的,反爬常用)
- cookie:本地字符串数据信息(用户登录信息,反爬的token)
- 响应头
- cookie:本地字符串数据信息(用户登录,反爬的token)
- 各种神奇莫名其妙的字符串(一般都是token字样,防止各种攻击和反爬)
4、Requests入门
- 安装requests第三方库
或者使用国内源,搜索清华源
https://mirrors.tuna.tsinghua.edu.cn/
语法:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 要下载的库
4.1、爬取网页名字信息
- 使用requests(手写一个小爬虫)
import requests
query=input("输入一个名字:")
url=f"https://www.baidu.com/s?ie=UTF-8&wd={query}"
dic={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"
}#拿到头文件,模拟浏览器
resp=requests.get(url,headers=dic)#处理小爬虫
print(resp.text)
4.2、爬取百度翻译
找到相对应需要爬取的数据url,然后进行爬虫
import requests
url="https://fanyi.baidu.com/sug"
s=input("请输入需要翻译的单词")
dat={
"kw":s
}
# 发送post请求,发送的数据必须放在字典中,通过打他参数进行传递
resp=requests.post(url,data=dat)
# print(resp.text)这个是输出乱码,因此直接使用json
# 将服务器返回内容直接处理成json()=>dict
print(resp.json())
4.3、豆瓣信息爬取
import requests
url="https://movie.douban.com/j/search_subjects"
# 封装参数
param={
"type": "movie",
"tag": "日本",
"sort": "recommend",
"page_limit": 20,
"page_start": 0,
}
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"
}
resp=requests.get(url=url,params=param,headers=headers)
print(resp.json())
resp.close()#关闭resp
5、数据解析
三种解析方式:
- re解析
- bs4解析
- xpath解析
5.1、RE解析
5.1.1、正则表达式
- 常见的元字符
\\d 表示所有的字数
\\w 表示大小写字符、数字、下划线
\\s 表示空白、空格、换行符、制表符
\\t 匹配制表符
\\n 匹配换行符
\\D 表示所有的非数字
\\W 表示除数字字符下划线之外的所有字符
\\S 表示非空白
. 表示除了换行符之外的任意内容
[ ]字符组:只要在中括号内的所有字符都是符合规则的字符
[^ ]非字符组:只要在中括号内的所有字符都是不符合规则的字符
^ 表示一个字符的开始
$ 表示一个字符的结束
| 表示"或",注意,如果两规则有重叠部分,总是长得在前面,短的在后面
()表示分组,给一部分正规则为一组,|这个符号的作用域就可以缩小了
[\\d\\D] [\\w\\W] [\\s\\S] 匹配一切字符
- 多多使用正则表达式工具测试
https://c.runoob.com/front-end/854
量词
{n} 表示只能出现n次
{n,} 表示至少出现n次
{n,m}表示至少出现n次,至多出现m次
?表示匹配0次或者1次,表示可有可无 但是只能有一个,比如小数点
+表示匹配1次多着或者多次
*表示匹配0次或者多次,表示可有可无,但是有可以有多个,比如小数点后n位
贪婪匹配和惰性匹配
.* 贪婪匹配
.*? 惰性匹配 //爬虫常用
5.1.2、python运用re模块
- findall查询所有,返回list
- search会进行匹配,但是如果匹配到了第一结果就会返回,反之
- match只能从字符串的开头进行匹配
- finditer和findall雷同,差别是findall是迭代器
import re
# findall匹配字符串中所有符合的内容
lst=re.findall(r"\\d+","我的密码是:100100,女朋友的密码:100180")
print(lst)
# finditer匹配字符串中所有的内容[返回的是迭代器],从迭代器中拿到内容需要.group()
it=re.finditer(r"\\d+","我的密码是:100100,女朋友的密码:100180")
for i in it:
print(i.group())
# search,找到一个结果就返回,返回的是match对象,拿数据需要.group()
s=re.search(r"\\d+","我的密码是:100100,女朋友的密码:100180")
print(s.group())
# match是从头开始匹配,注意此时我
h=re.match(r"\\d+","100100,女朋友的密码:100180")
print(h.group())
# 预加载正则表达式
m=re.compile(r"\\d+")
result=m.findall("我的密码是:100100,女朋友的密码:100180")
print(result)
5.1.3、爬取网页独有信息
s="""
<div class='jar'><span id='1'>语文</spam></div>
<div class='jsa'><span id='2'>数学</spam></div>
<div class='ds'><span id='3'>英语</spam></div>
<div class='jsr'><span id='4'>生物</spam></div>
"""
# ?P<任意>:作为一种标识,最后输出
h=re.compile(r"<div class='.*?'><span id='.*?'>(?P<class>.*?)</spam></div>")
result=h.finditer(s)
for i in result:
# 根据上方定义取出
print(i.group("class"))
5.1.4、爬取豆瓣电影实战
import requests
import re
import csv
url="https://movie.douban.com/chart"
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"
}
resp=requests.get(url,headers=headers)
page_context=resp.text
s=re.compile('<p class="ul"></p>.*?title="(?P<score>.*?)">.*?<span class="rating_nums">(?P<score1>.*?)</span>.*?"pl">(?P<num>.*?)</span>',re.S)
result=s.finditer(page_context)
f=open("data.csv",mode="w",encoding="utf-8")
csvwrite=csv.writer(f)
for it in result:
dic=it.groupdict()
csvwrite.writerow(dic.values())
# print(it.group("score","score1","num"))
5.1.5、爬取屠戮电影实战
import requests
import re
domain="https://www.dytt89.com/"
resp=requests.get(domain)
resp.encoding="gb2312"
# print(resp.text)
obj1=re.compile(r'<div class="co_area2".*?<ul>(?P<m_name>.*?)</ul>',re.S)
obj2=re.compile(r"<li><a href='(?P<load>.*?)'",re.S)
obj3=re.compile(r'◎片 名(?P<m_name2>.*?)<br.*?<td style="WORD-WRAP: break-word" bgcolor="#fdfddf"><a href="(?P<down>.*?)">magnet',re.S)
result1=obj1.finditer(resp.text)
num=[]
for i in result1:
h=i.group("m_name")
# print(h)
result2=obj2.finditer(h)
for l in result2:
# ,拼接子页面的url地址:域名+子页面地址
load = domain+l.group("load").strip("/")
# print(load)
num.append(load) #保存起来
# 提取子页面的内容
for m in num:
m_name2=requests.get(load)
m_name2.encoding='gb2312'
result3=obj3.search(m_name2.text)
print(result3.group("m_name2"))
print(result3.group("down"))
5.2、BS4解析
5.2.1、爬取北京菜市价
import requests
from bs4 import BeautifulSoup
url="http://www.bjtzh.gov.cn/bjtz/home/jrcj/index.shtml"
resp=requests.get(url)
resp.encoding="utf-8"
# 解析数据
# 把数据变为bs4数据处理,生成bs对象
page=BeautifulSoup(resp.text,"html.parser")
# print(page)
# 从bs4对象中查询数据
# find(标签,属性=值)
# find_all(标签,属性=值)
table=page.find("table",style="margin: 0px auto; width: 588px; height: 847px; border-collapse: collapse;")
# table=page.find("table",align="center")
# print(table)
# 拿到所有的数据行
trs=table.find_all("tr")[1:]
for tr in trs:
tds=tr.find_all("td")#拿到所有的td
name=tds[0].text
# kinds=tds[1].text
maxPrice=tds[1].text
avgPrice=tds[2].text
print(name,maxPrice,avgPrice)
5.2.2、爬取网上图片
# 找到页面源代码,然后提取到子页面的链接地址,href
# 通过href拿到子页面内容,从子页面找到图片下载地址
import requests
from bs4 import BeautifulSoup
url="https://www.umei.net/weimeitupian/"
resp=requests.get(url)
resp.encoding="utf-8" #乱码处理
# print(resp.text)
# 数据处理
page=BeautifulSoup(resp.text,"html.parser")
alist=page.find("div",class_="TypeList").find_all("a")
# print(alist)
href=[]
for a in alist:
load=url+a.get('href').strip("/weimeitupian")+"tm"
# print(load)
href.append(load)#保存到容器中
# href=a.get(load)#直接通过get爬取属性的值
# 拿到源代码
for page_img in href:
child_img=requests.get(load)
child_img.encoding='utf-8'
child_text=child_img.text
# print(child_img.text)
# 拿到图片的下载路径
page_img=BeautifulSoup(child_text,"html.parser")
p=page_img.find("p",align="center")
img=p.find("img")
src=img.get("src")
# page_resp=requests.get(href)
# page_resp.encoding='utf-8'
# print(page_resp.text)
# page_text=page_resp.text
# img=page_2("img")
# src=img.get("src")
# 下载图片
img=requests.get(src)
img_name=src.split("/")[-1]#拿到url中最后/一个内容
with open("img/"+img_name,mode="wb")as f:
f.write(img.content)#拿到图片字节,并写入文件
6、Xpath解析
6.1、初识Xpath
Xpath是在xml文档中搜索内容的一门语言
html是xml的一个子集
安装xpath:pip install lxml
准备一个xml文件
xml="""
<book>
<id>1</id>
<name>加油别放弃</name>
<arice>1.123</arice>
<nick>加油</nick>
<author>
<nick id="199">别放弃</nick>
<nick id="139">别</nick>
<nick class="jos">放</nick>
<nick class="da">弃</nick>
<div>
<nick>你懂</nick>
</div>
</author>
<partner>
<nick id="12">胖乎乎</nick>
<nick id="12asd">胖乎asd乎</nick>
</partner>
</book>
"""
from lxml import etree
xml="""将上方文件放入其中"""
tree=etree.XML(xml)
# result=tree.xpath("/book")
# result=tree.xpath("/book/name")
# result=tree.xpath("/book/name/text()")#text()获取其中的文本
# result=tree.xpath("/book/author//nick/text()")#//代表的是父节点下的所有子节点都可以被包含
# result=tree.xpath("/book/author/*/nick/text()")//*是通配符,代表任意一个节点
result=tree.xpath("/book//nick/text()")
print(result)
6.2、Xpath实现对HTML的小爬虫
首先准备一个HTML文件,注意要在meta加上/作为标签结束,否则报错
成功后的效果图如下
from lxml import etree
tree=etree.parse("xml.html")#获取HTML文本,读取数据
# 括号里面的标签意思:<>内容</>,读取表亲啊中间的所有内容
# result=tree.xpath("/html")#将HTML标签中的所有东西整理
# result=tree.xpath("/html/body//author/nick/text()")
# result=tree.xpath("/html/body//author/nick[1]/text()")#需要注意的是,xpath的顺序是从1开始的
kind=tree.xpath("/html/body//author")
for i in kind:
#从每一个nick里拿到文字信息
# result=i.xpath("./id/text()")#./是绝对路径
result=i.xpath("./nick/@id")
print(result)
6.3、xpath实战(猪八戒网爬虫)
#获取网站地址
# 数据分析
import requests
from lxml import etree
url="https://foshan.zbj.com/search/f/?kw=%E5%95%86%E6%A0%87%E8%AE%BE%E8%AE%A1&fr=zbj.sy.zyyw_1st.lv3"
resp=requests.get(url)
# print(resp.text)
# 数据解析
html=etree.HTML(resp.text)
kinds=html.xpath("/html/body/div[6]/div/div/div[3]/div[5]/div[1]/div")#获取到网站中的每一个产品的xpath
for i in kinds:#包含每一个商品的的用户信息
# price=i.xpath("./div/div/a/div[2]/div[1]/span[1]/text()")[0].strip("¥")
text="logo".join(i.xpath("./div/div/a/div[2]/div[2]/p/text()"))#join可以拼接产品中的黄色标签
# print(price)
print(text)
7、Requests进阶
7.1、登录网站爬虫
首先,准备一个自己写的网页,如果没有,我可以分享一份,登录时候,可以发现,用户名和密码已经存在cookie
# 登录得到cookie
# 带着cookie去请求用户列表url
# 必须把上面两个操作连接起来
# 我们可以使用session请求,在这个过程中,cookie不会消失
import requests
session=requests.session()
data={
"userCode": "admin",
"userPassword": "123456",
}
# 一、通过用户名密码抓取数据
# # 1、登录
# url="http://localhost:8080/login.do"
# session.post(url,data=data)
# # print(resp.text)
#
# #2、拿到用户列表信息
# # session已经是存在cookie的,以此,我们可以直接获取
# resp=session.get('http://localhost:8080/jsp/user.do?method=query')
# print(resp.text)
#二、通过cookie来爬取
resp=requests.get('http://localhost:8080/jsp/user.do?method=query',headers={
"Cookie": "Pycharm-9b2f2c98=1ec03cda-8466-40b0-9ece-535dc5b71cd4; JSESSIONID=9A7B386209342505265729B2B5E1D0F9"
})
print(resp.text)
7.2、防盗链(梨视频爬虫)
视频爬虫原理
# 1.拿到contId
# 2.拿到videoStatus返回的json->srcURL
# 3.srcURL里面的内容进行修正
# 4.下载视频
import requests
url="https://www.pearvideo.com/video_1731807"
contId=url.split("_")[1]#_前面的为[0],_后面的为[1]
videoStatus=f"https://www.pearvideo.com/videoStatus.jsp?contId={contId}&mrd=0.014195653140843811"
resp=requests.get(videoStatus)
print(resp.text)
出现以上这种情况是因为在防盗链的作用下,我们就应该还给他一个溯源
# 1.拿到contId
# 2.拿到videoStatus返回的json->srcURL
# 3.srcURL里面的内容进行修正
# 4.下载视频
import requests
url="https://www.pearvideo.com/video_1731807"
contId=url.split("_")[1]#_前面的为[0],_后面的为[1]
videoStatus=f"https://www.pearvideo.com/videoStatus.jsp?contId={contId}&mrd=0.014195653140843811"
headers={
#防盗链,当前请求的上一级是谁
"Referer": url #"https://www.pearvideo.com/video_1731807"
}
resp=requests.get(videoStatus,headers=headers)
dic=resp.json()
srcUrl=dic['videoInfo']['videos']['srcUrl']
systemTime=dic['systemTime']
srcUrl=srcUrl.replace(systemTime,f"cont-{contId}")
print(srcUrl)
# 下载视频
with open("a.mp4",mode="wb")as f:
f.write(requests.get(srcUrl).content)
7.3、代理
#原理:通过第三方的一个机器请求
# 慎用代理,不必时尽量不用
import requests
proxies={
"https": "https://122.51.207.244:8888"#此处为代理的IP地址
}
resp=requests.get("https://www.baidu.com",proxies=proxies)
resp.encoding="utf-8"
print(resp以上是关于python爬虫从入门到放弃,含案例分析,超详细讲解的主要内容,如果未能解决你的问题,请参考以下文章
Python爬虫从入门到放弃之 Scrapy框架整体的一个了解