目录
day01回顾
1.请求模块(urllib.request)
- Request(url,data=data,headers=headers)
- urlopen(请求对象)
2.响应对象res的方法
- res.read() ##数据类型:bytes
res.read().decode('utf-8') ##数据类型:string - res.getcode()
- res.geturl()
3.url编码模块(urllib.parse)
- urlencode(字典)
原始数据:kw={'kw':'只手遮天'}
urlencode后:kw=%e8%%e5%d3... #字符串 - quote(字符串)
s= '只手遮天'
quote后:%e8%%e5%d3...
- unquote()
4.数据爬取步骤
- 找URL(拼接)
- 获取响应内容
- 保存
5.请求方式
- GET:查询参数在URL地址上显示
- POST(参数名data):查询参数在Form表单里
注意:data一定腰围bytes数据类型
data = {...}
data = urlencode(data)
data = bytes(data,'utf-8') #字符串 - 字节流
data.encode('utf-8')
day02
1.解析
- 数据的分类
- 结构化数据
特点:有固定的格式,如:HTML,XML,JSON - 非结构化数据
示例:图片,音频,视频,这类数据一般都存储为二进制
- 结构化数据
- 正则表达式re
- 使用流程
- 创建编译对象:p = re.compile('正则表达式')
- 对字符串匹配:r = p.math('字符串')
- 获取匹配结果:print(r.group())
- 常用方法
- match(s):字符串开头的第一个返回对象
- search(s):从开始往后找,匹配第1个,返回对象
- group():从match或search返回对象中取值
- findall():所有全部匹配,返回一个列表
- 表达式
. 匹配任意字符(不能匹配\n)
\d 数字
\s 空白字符
\S 非空白字符
[...] 包含[]内容:A[BCD]E -- ABE --ACE --ADE
\w 字母,数字_
* 0次或多次
?0次或1次
+ 1次或多次
{m} m次
{m,n} m-n次 AB{1,3}C -- ABC ABBC ABBBC
贪婪匹配(.*) :在整个表达式匹配成功的前提下,尽可能多的匹配*
非贪婪匹配(.*?):在整个表达式匹配成功的前提下,尽可能少的匹配*
- 示例(贪婪模式和非贪婪模式)示例
import re s = """<div><p>仰天大笑出门去,我辈岂是蓬蒿人</div></p> <div><p>床前明月光,疑是地上霜</div></p>""" # 创建编译对象 # re.S作用 :使 . 能够匹配 \n 在内的所有字符 # 贪婪匹配 : .* p = re.compile('<div><p>.*</div></p>',re.S) #非贪婪匹配 : .*? p = re.compile('<div><p>.*?</div></p>',re.S) # 匹配字符串s r = p.findall(s) print(r) #["<div><p>仰天大笑出门去,我辈岂是蓬蒿人</div></p>", # "<div><p>床前明月光,疑是地上霜</div></p>"]
- findall()的分组
import re #解释 :先按照整体匹配出来,然后再匹配()中的 # 如果有2个或者多个(),则以元组的方式取显示 s = "A B C D" p1 = re.compile('\w+\s+\w+') print(p1.findall(s)) # ['A B','C D'] p2 = re.compile('(\w+)\s+\w+') # 第1步 :['A B','C D'] # 第2步 :['A','C'] print(p2.findall(s)) p3 = re.compile('(\w+)\s+(\w+)') # 第1步 :['A B','C D'] # 第2步 :[('A','B'),('C','D')] print(p3.findall(s))
- 练习
import re s = """<div class="animal"> <p class="name"> <a title="Tiger"></a> </p> <p class="contents"> Two tigers two tigers run fast </p> </div> <div class="animal"> <p class="name"> <a title="Rabbit"></a> </p> <p class="contents"> Small white rabbit white and white </p> </div>""" p = re.compile('<div class="animal".*?title="\ (.*?)">.*?contents">(.*?)</p>',re.S) r = p.findall(s) #print(r) for animal in r: print("动物名称:",animal[0].strip()) print("动物描述:",animal[1].strip())
- 案例1:内涵段子脑筋急转弯抓取
网址:www.neihan8.com
步骤:- 找URL规律
第一页 https://www.neihan8.com/njjzw/index.html
第二页 https://www.neihan8.com/njjzw/index_2.html
第三页 https://www.neihan8.com/njjzw/index_3.html - 用正则匹配出 题目 和 答案
p = re.compile('<div class="text-.*?title="(.*?)".*?<div class="desc">(.*?)</div>',re.S) - 写代码
- 发请求
- 用正则匹配
- 写入本地文件
import urllib.request import re class NeihanSpider: def __init__(self): self.baseurl = "https://www.neihan8.com/njjzw/" self.headers = {"User-Agent":"Mozilla/5.0"} self.page = 1 # 下载页面 def loadPage(self,url): req = urllib.request.Request(url,headers=self.headers) res = urllib.request.urlopen(req) html = res.read().decode("utf-8") self.parsePage(html) # 解析页面 def parsePage(self,html): p = re.compile('<div class="text-.*?title="(.*?)".*?<div class="desc">(.*?)</div>',re.S) r_list = p.findall(html) # [("什么动物...","海豹"),(),()...] self.writePage(r_list) # 保存页面 def writePage(self,r_list): for r_tuple in r_list: for r_str in r_tuple: with open("急转弯.txt","a",encoding="gb18030") as f: f.write(r_str.strip() + "\n") with open("急转弯.txt","a",encoding="gb18030") as f: f.write("\n") def workOn(self): self.loadPage(self.baseurl) while True: c = input("成功,是否继续(y/n):") if c.strip().lower() == "y": self.page += 1 url = self.baseurl + "index_" +\ str(self.page) + ".html" self.loadPage(url) else: print("爬取结束,谢谢使用!") break if __name__ == "__main__": spider = NeihanSpider() spider.workOn()
- 找URL规律
- 猫眼电影top100榜单,存到csv表格文件中
网址:猫眼电影 - 榜单 - top100榜
目标:抓取电影名,主演,上映时间- 知识点讲解
- csv模块的使用流程
- 打开csv文件
with open('测试.csv','a') as f: - 初始化写入对象
writer = csv.writer(f) - 写入数据
writer.writerow(列表)
- 打开csv文件
- 示例
'''05_csv示例.py''' import csv with open("猫眼.csv","a",newline="") as f: # 初始化写入对象 writer = csv.writer(f) #把列表写入到文件中 writer.writerow(["电影名称","主演"]) writer.writerow(["霸王别姬","张国荣"]) writer.writerow(["唐伯虎点秋香","周星驰"])
- csv模块的使用流程
- 准备工作
- 找URL
第一页:http://maoyan.com/board/4?offset=0
第二页:http://maoyan.com/board/4?offset=10
第三页:http://maoyan.com/board/4?offset=20
第n页:offset = (n-1)*10 - 正则匹配
<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?releasetime">(.*?)</p>
- 找URL
- 写代码
'''06_猫眼电影top100抓取.py''' import urllib.request import re import csv class MaoyanSpider: def __init__(self): self.baseurl = "http://maoyan.com/board/4?offset=" self.headers = {"User-Agent":"Mozilla/5.0"} self.page = 1 self.offset = 0 # 下载页面 def loadPage(self,url): req = urllib.request.Request(url,headers=self.headers) res = urllib.request.urlopen(req) html = res.read().decode("utf-8") self.parsePage(html) # 解析页面 def parsePage(self,html): p = re.compile('<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?releasetime">(.*?)</p>',re.S) r_list = p.findall(html) # print(r_list) # [("霸王别姬","张国荣","1994-01-01"),(),()...] self.writePage(r_list) def writePage(self,r_list): if self.page == 1: with open("猫眼电影.csv","a",newline="",encoding='gb18030') as f: writer = csv.writer(f) writer.writerow(["电影名称","主演","上映时间"]) for r_tuple in r_list: with open("猫眼电影.csv","a",newline="",encoding='gb18030') as f: # 创建写入对象 writer = csv.writer(f) # L = list(r_tuple) L = [r_tuple[0].strip(),r_tuple[1].strip(),r_tuple[2].strip()] # ["霸王别姬","张国荣","1994-01-01"] writer.writerow(L) def workOn(self): while True: c = input("爬取请按y(y/n):") if c.strip().lower() == "y": self.offset = (self.page-1)*10 url = self.baseurl + str(self.offset) self.loadPage(url) self.page += 1 else: print("爬取结束,谢谢使用!") break if __name__ == "__main__": spider = MaoyanSpider() spider.workOn()
- 知识点讲解
- 使用流程
2.Fiddler常用菜单
- Inspector:查看抓到的数据包的详细内容
- 分为请求(request)和响应(response)两部分
- 常用选项
- Haders:显示客户端发送到服务器的header,包含客户端信息,cookie,传输状态
- WebForms:显示请求的POST数据<body>
- Raw:将整个请求显示为纯文本
3.请求方式及案例
- GET
- POST
- Cookie 模拟登陆
- 什么是cookie,session
HTTP是一种无连接协议,客户端和服务器交互仅仅限于 请求/响应过程,结束后断开,下一次请求时,服务器会认为是一个新的客户端,为了维护他们之间的链接,让服务器知道这是前一个用户发起的请求,必须在一个地方保存客户端信息
cookie:通过在客户端记录的信息确定用户身份
session:通过在服务端记录的信息确定用户身份 - 案例:使用cookie模拟登陆人人网
步骤:- 通过抓包工具,f12获取到cookie(先登陆1次网站)
- 正常发请求
url:http://www.renren.com/967469305/profile'''07_cookie模拟登陆人人网.py''' import urllib.request url = "http://www.renren.com/967469305/profile" headers = { "Host":"www.renren.com", "Connection":"keep-alive", "Upgrade-Insecure-Requests":"1", "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", "Referer":"http://www.renren.com/", # Accept-Encoding: gzip, deflate "Accept-Language":"zh-CN,zh;q=0.9", "Cookie":"anonymid=jnoaljpk7d3nh2; depovince=BJ; _r01_=1; _de=4DBCFCC17D9E50C8C92BCDC45CC5C3B7; ln_uact=13603263409; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; jebe_key=1b1f4a34-0468-4185-a3b0-6f2c38abc368%7C2012cb2155debcd0710a4bf5a73220e8%7C1540454149943%7C1%7C1540454153787; wp_fold=0; wp=0; jebecookies=2fc339e7-1b51-43ce-bc85-e2dc1f68ee16|||||; JSESSIONID=abcANrnqoMuLshY34pQAw; ick_login=30d0bd58-f6bb-437f-8d0d-6a72ae00e7b7; p=1e1b85cb8dda387a70e400a341c2e9c95; first_login_flag=1; t=4f652cc0a8f3fd50f5c9095c92d4717d5; societyguester=4f652cc0a8f3fd50f5c9095c92d4717d5; id=967469305; xnsid=55bff2d5; loginfrom=syshome" } req = urllib.request.Request(url,headers=headers) res = urllib.request.urlopen(req) print(res.read().decode("utf-8"))
- 什么是cookie,session
4.requests模块
- 安装(用管理员身份去打开才Anaconda Prompt)
Anaconda:conda install requests
Window cmd : python -m pip install requests
##以管理员身份去执行pip安装命令 - 常用方法
- get(url,headers=headers):发起请求,获取响应对象
- response属性
- response.text:返回字符串类型
- response.content:返回bytes类型
- 应用场景:爬取非结构化数据
- 示例:图片保存
import requests url = "http://dingyue.nosdn.127.net/LftiDijLShX6y8NWnEI606fo0TJmFMRIByj4HniV9GypR1539753512019.jpg" headers = {"User-Agent":"Mozilla/5.0"} res = requests.get(url,headers=headers) html = res.content with open("颖宝.jpg","wb") as f: f.write(html) print("图片下载成功")
- response.encoding
网站一般返回:ISO-8859-1
response.encoding = 'utf-8'
手动返回utf-8 - response.status_code:返回服务器响应码
- response.url:返回数据URL地址
'''08_requests模块示例.py''' import requests url = "http://www.baidu.com/" headers = {"User-Agent":"Mozilla/5.0"} # 发请求获响应 response = requests.get(url,headers=headers) response.encoding = "utf-8" # 获取字符串 print(type(response.text)) # 获取字节流 print(type(response.content)) # 返回服务器响应码 print(response.status_code) # 返回数据的URL print(respone.url) #print(respone.encoding) # 默认返回编码格式 :ISO-8859-1
- get()使用场景
- 没有查询参数
res = requests.get(url,headers=headers) - 有查询参数:params={}
注:params参数必须为字典,自动进行编码
示例见:'''09_requests.get.params.py''' import requests headers = {"User-Agent":"Mozilla/5.0"} url = "http://www.baidu.com/s?" key = input("请输入要搜索的内容:") params = {"wd":key} # 自动编码,自动拼接URL,params必须为字典 res = requests.get(url,params=params,headers=headers) # 指定utf-8 res.encoding = "utf-8" print(res.text)
- 没有查询参数
- post() 参数名:data
- data = {}
- 示例 有道翻译
'''10_有道翻译post.py''' import requests import json # 请输入你要翻译的内容 key = input("请输入要翻译的内容:") # post方法要求data为字典格式 data = {"i": key, "from":"AUTO", "to":"AUTO", "smartresult":"dict", "client":"fanyideskweb", "salt":"1540373170893", "sign":"a5d9b838efd03c9b383dc1dccb742038", "doctype":"json", "version":"2.1", "keyfrom":"fanyi.web", "action":"FY_BY_REALTIME", "typoResult":"false" } # 发请求,获取响应 # url为POST的地址,抓包工具抓到的,此处去掉 _o url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule" headers = {"User-Agent":"Mozilla/5.0"} # 此处data为form表单数据 res = requests.post(url,data=data,headers=headers) res.encoding = "utf-8" html = res.text # 把json格式字符串转换为Python中字典 r_dict = json.loads(html) result = r_dict['translateResult'][0][0]["tgt"] print(result) # 作业 :把翻译后的结果输出来 # 请输入要翻译的内容 :你好 # hello #{'type': 'ZH_CN2EN', # 'errorCode': 0, # 'elapsedTime': 7, # 'translateResult': # [[{'src': '风云', 'tgt': 'Occasion'},{}],[]] #}
作业:
- 改写代码,用requests模块实现
- 链家二手房https://bj.lianjia.com/ershoufang/pg1/
- 百度搜索 链家 -> 二手房
- 爬取 :小区名称、总价
今日示例