任务1.1——请求
get请求中的参数 跟在URL后,所以,数据可以在URL后面查看(暴露敏感信息)
post请求中,请求的内容通过form表单传输,URL部分不会包含这些内容(内容在 http响应中的请求体中)——请求数据常用get,提交数据常用post
get请求提交的数据 <= 1024字节,post请求没有限制
通过 requests的get方法可以发送请求 给某个URL
post同理
(1)
以下代码即可 发送请求给百度URL
并且获得 URL响应的 内容
import requests
page = requests.get('http://www.baidu.com/')
print (page.content)
print (requests.get('http://www.baidu.com/').text)
(2)
如果断开了网络,那么请求网页不成功
import requests
page = requests.get('http://www.baidu.com/')
print (page.status_code)
输出
raise ConnectionError(e, request=request)
ConnectionError: HTTPConnectionPool(host='www.baidu.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x0000022076150EB8>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed'))
状态码分为五大类:
100-199 用于指定客户端应相应的某些动作。
200-299 用于表示请求成功。
300-399 用于 已经移动的文件 并且 常被包含在定位头信息中 指定新的地址信息。
400-499 用于指出客户端的错误。
500-599 用于支持服务器错误。
具体见:
http://www.cnblogs.com/lxinxuan/archive/2009/10/22/1588053.html
(3)
请求头 说明服务器要使用的附加信息,用于传递头信息,以便模拟浏览器工作
如果不添加请求头,可能无法正常请求
请求头信息有:
Accept:客户端能接受的 内容类型
Accept-Encoding:可支持返回的 内容压缩编码类型(接受什么编码方法)通常有:是否支持压缩、指定压缩方法
Accept-Language:指定 返回信息时优先选择的语言(接受什么语言)
Connection:是否需要持久连接
Connection:keep-alive 连接不关闭,再访问无需重连,而Connection:close则需要重连(TCP连接)
Cookie:发送请求时,会把保存在请求域下的所有cookie值 发送给web服务器
Host:请求的 web服务器 域名地址
Referer:用户从 包含的URL页面出发,访问 当前请求的页面服务器端——告诉服务器 从那个页面URL来的
User-Agent:当前HTTP请求的 客端户浏览器的名称和版本
设置请求头信息:
headers={
'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6) ',
'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language' : 'en-us'
}
任务1.2——正则表达式
正则表达式:用已定义好的规则将 特定的文本 提取出来(解析工具——提取想要的内容)
可以实现 字符串的检索、替换和匹配验证
贪婪匹配模式:. * ——总是匹配尽量多的字符
非贪婪匹配:. *?——总是匹配尽可能少的字符
通常采用非贪婪模式匹配
r: 表示字符串为非转义的原始字符串
re模块————用于支持正则表达式
re.compile(string[, flags]) #把 str 编译成 pattern(正则表达式对象),以供匹配
#以下为匹配函数
re.match(pattern, string,flags=0)
向它传入 正则表达式 以及 要匹配的字符串,
就可以检测 此正则是否匹配字符串
(参数一(正则) + 参数二(要匹配字符串))
匹配过程:从开头开始匹配,一旦有不符合正则的则匹配失败(错误or长度不足)
∴更适合用来检测某个字符串是否符合某个正则表达式的规则
import re
print (re.match('.*','hello world'))
注:flags:(控制正则表达式的)匹配模式
re.I
使匹配对大小写不敏感
re.L
做本地化识别(locale-aware)匹配
re.M
多行匹配,影响^和$
re.S
使.匹配包括换行在内的所有字符
re.U
根据Unicode字符集解析字符。这个标志影响\w、\W、 \b和\B
re.X
详细模式,该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解
re.search
正则表达式可以是字符串的一部分,
在匹配时,search()方法会依次扫描字符串,直到找到第一个符合规则的字符串,然后返回匹配内容,如果搜索完了还没有找到,就返回None
re.findall
搜索整个字符串,然后返回 匹配正则表达式的所有内容
re.finditer
搜索整个字符串,返回一个迭代器(一个顺序访问 每一个匹配的结果的迭代器)
for a in re.finditer()
re.sub
re.sub(pattern,repl,string,count=0, flags=0)
使用repl替换 string中 的匹配(pattern)项
注:
count : 替换的最大次数,默认 0 表示全部替换
实战——爬取豆瓣电影
# 请求网页(得到源代码),解析(提取)需要的信息,保存下来
# 分步完成,先提取一页的信息,再想办法 转页 查询
# 目标:名次、影片名称、年份、导演 ——正则提取
import requests
import re #用到的库、模块
headers={
'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6) '
}
def one_page_suss(url):
page = requests.get(url)
roo= page.text #指定变量
#写各个正则 相当于草稿
rank = re.findall('<em class="">(\d+)</em>',roo,re.S)
name = re.findall('<span class="title">([\u4e00-\u9fa5]+)</span>',roo,re.S)
text = re.sub('导演: ',"",roo) #可以把“导演:”去掉
director = re.findall('<p class="">(.*?) ', text, re.S)
time = re.findall('<br>(.*?) ',roo,re.S)
#把一部电影的信息 合成一条输出 √ 草稿合成
all_want = re.findall('<em class="">(\d+)</em>.*?<span class="title">([\u4e00-\u9fa5]+)</span>.*?<p class="">(.*?) .*?<br>(.*?) ',roo,re.S)
print(all_want)
# 保存文件成TXT,以下代码IDE中显示无错
f=open('tasklist.txt','w')
f.write(str(all_want))
f.close()
#所有的页面 都进行以上方法
for i in range(0,250,25):
url = 'https://movie.douban.com/top250?start={0}&filter='.format(i)
one_page_suss(url)
最大的问题1:为什么我运行会输出——了解编码问题
UnicodeEncodeError: 'gbk' codec can't encode character '\xf6' in position 1094: illegal multibyte sequence
方法:
找到了一种f=open('tasklist.txt','w',encoding='utf-8')
改成这样就可以运行
但是又有一个新问题,为什么 保存的文件 有且只有 一页的电影?而且这一页还不确定(比如说:运行一次保存的是226到250,第二次又保存的是51到75)——
把 ‘w’改成’a’:因为我是循环one_page_suss方法,所以每一次w,后面内容就会覆盖前面的内容,而使用a则是追加,理想中就可以追加十次内容,但多数时候下面的代码也只能输出200+条,而不是250条
f=open('tasklist.txt','a',encoding='utf-8')
f.write(str(all_want))
f.close()
群友提供的办法,f.write内容改成如下
f=open('tasklist.txt','a',encoding='utf-8')
f.write("\n".join(str(i) for i in all_want))
f.close()
效果:结构化数据,并且绝大多数时候输出全部数据(250)——多加以理解
学长质疑:all_want中list 夹着turple (他提供了 f.write("\n".join(i for i in all_want))) ——没看懂※以后解决掉
问题2:为什么写正则的时候 末尾带上 才能正常输出结果,否则输出个空列表?
总结:
作业流程——
1:预先工作(import、设置请求头)
2:请求页面(get/post)获得源代码
3:观察源代码,结合目标 构造 正则表达式对象(pattern),以供匹配
4:将匹配的结果进行 写入
5:利用循环,对各个页面做 以上流程
优化:
结构化数据(用字典、然后转成json格式)