网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者)
按照一定规律,自动地抓取万维网信息的程序或者脚本。
爬虫只能用python写吗?其实不然,用Java,c都能写,只不过python对于小白上手快,就像吃饭一般,筷子、勺子、甚至用手抓,他都是可以的,但是大家也都知道筷子勺子吃又优美雅观而且干净。
合法!他就像是小刀的存在,小刀可以给人类带来便利,带来一点点危害,也可能会带来很大的危害,没有什么物品是错误的,有的是使用的人,怎么使用,这是关键!
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!")
超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议
它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。
请求和响应消息的头以ASCII形式给出;而消息内容则具有一个类似MIME的格式。
或者使用国内源,搜索清华源
https://mirrors.tuna.tsinghua.edu.cn/
语法:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 要下载的库
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)
找到相对应需要爬取的数据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())
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
三种解析方式:
\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位
贪婪匹配和惰性匹配
.* 贪婪匹配
.*? 惰性匹配 //爬虫常用
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)
s="""
语文
数学
英语
生物
"""
# ?P<任意>:作为一种标识,最后输出
h=re.compile(r"(?P.*?) ")
result=h.finditer(s)
for i in result:
# 根据上方定义取出
print(i.group("class"))
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('.*?title="(?P.*?)">.*?.*?) .*?"pl">(?P',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"))
import requests
import re
domain="https://www.dytt89.com/"
resp=requests.get(domain)
resp.encoding="gb2312"
# print(resp.text)
obj1=re.compile(r'(?P.*?)',re.S)
obj2=re.compile(r",re.S)
obj3=re.compile(r'◎片 名(?P.*?)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>1id>
<name>加油别放弃name>
<arice>1.123arice>
<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.text)