作者讲了两个库,一个是urllib,一个是requests。因为后者更为方便,强大,直接看requests就好
3.2 使用 requests
请求网页: r = requests.get(url,params=data)
是否得到响应:r.status_code
返回的结果如果是str类型,可以用json()解析并返回字典格式,但如果不是str类型,会抛出异常
r.content: 返回抓取对象的二进制码,这样知道链接就可以获取图片,音乐和视频,因为它们本质上就是二进制数据…(暗爽~)
import requests
r = requests.get('https://www.baidu.com/img/bd_logo1.png')
with open('bdlogo.png','wb') as f:
f.write(r.content)
有些网站不给爬,我们就得修改headers
先给headers一个值,字典类型,如:
headers={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36(KHTML,like Gecko) '
'Chrome/65.0.3325.162 Safari/537.36'}
r.requests.get(url,headers=headers)
r.requests.post():跟get差不多,不过get就是在网址后面加数据,post能发送数据和文件,用的是字典类型
files = {'file':open('bdlogo.png','rb')} # 以二进制的形式打开文件
r = requests.post("http://httpbin.org/post",files=files)
r.cookies:获取cookies,作用是保持网站的登录状态。先登录一次网站,然后然cookies内容复制下来,粘贴到headers里
headers = {'Cookies': '粘贴Cookies',
'Host':'www.zhihu.com',
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36(KHTML,like Gecko) '
'Chrome/65.0.3325.162 Safari/537.36'}
r.requests.get(url,headers=headers)
这样就登录成功了
在用get()和post()时,是相当于用了两个浏览器打开网页。这样就会出现一个登录了网站,另一个没有登录的情况。这时我们就要用Session()
import requests
s = requests.Session()
s.get('http://httpbin.org/cookies/set/number/123456789')
r = s.get('http://httpbin.org/cookies')
print(r.text)
有些网站需要检查SSL证书,我们可以用verify=False参数来跳过,但会出现红字警告,我们可以采用忽略警告的方式
import requests
from requests.packages import urllib3
urllib3.disable_warnings()
r = requests.get(url,verify=False)
print(r.status_code)
网站对于频繁的请求,会弹出验证码,或封IP,这时需要用上代理。用socks5代理,需要先安装
requests[socks] 这个库
import requests
proxies = {
"http": "http://10.10.1.10:3128", # 代理纯属虚构
"https": "http://user:password@10.10.1.10:1080/", # 有些代理需要用户名和密码
"https": "socks5://user:password@host:port"
}
r = requests.get('https://www.taobao.com',proxies=proxies)
print(r.status_code)
有些网站特别是国外的,我们就设置超时,超过设置时间就报错, 还有些需要身份验证,输入用户名和密码的,用auth
r.requests.get(url, auth=('username','password'), timeout=10)
还可以想要发送的请求先打个包。然后一起发送出去。
from requests import Request,Session
url = 'http://httpbin.org/post'
data = {
'name': 'germey'
}
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36(KHTML,like Gecko) '
'Chrome/65.0.3325.162 Safari/537.36'
}
s = Session()
req = Request('POST', url, data=data, headers=headers)
prepped = s.prepare_request(req)
r = s.send(prepped)
print(r.text)
3.3 正则表达式
常用的匹配规则,有需要就翻一下,能记就记
通用匹配: 点星 .* ,能匹配所有任意字符,,但会涉及到贪婪匹配。避免贪婪就在*后面加个“?”。我们尽量做非贪婪匹配。
html节点经常会有换行,match(’’,content,re.S),用上re.S,就可以匹配节点与节点间的换行,
较常用的还有re.I,忽略大小写匹配
为了匹配方便,我们尽量使用search(),少用match
findall()获取 匹配的所有内容
sub()把不需要的字符去掉
3.4 抓取猫眼电影排行
抓取TOP100的电影名称、时间、评分、图片等
目标网址:https://maoyan.com/board/4
目标有分页,每页10部电影,点第二页观察网址的变化
第二页:https://maoyan.com/board/4?offset=10
第三页:https://maoyan.com/board/4?offset=20
…
…
可见,offset是偏移量,每页显示10个,显示 n+1 到 n+10 名次的电影。。要获取TOP100,就分开请求10次。然后用正则表达式提取相关信息
import requests
import re
import json
from requests.exceptions import RequestException
import time
def parse_one_page(html): # 正则提取
pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?name"><a'
+ '.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>'
+ '.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S)
items = re.findall(pattern, html)
for item in items: # 处理结果,遍历提取并生成字典
yield {
'index':item[0],
'image':item[1],
'title':item[2].strip(),
'actor':item[3].strip()[3:] if len(item[3]) > 3 else '',
'time':item[4].strip()[5:] if len(item[4]) > 5 else '',
'score':item[5].strip() + item[6].strip()
}
def get_one_page(url):
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36(KHTML,like Gecko) '
'Chrome/65.0.3325.162 Safari/537.36'
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.text
return None
except RequestException:
return None
def write_to_file(content): # 写入文件
with open('result.txt','a',encoding='utf-8') as f:
print(type(json.dumps(content))) # 实现字典的序列化
f.write(json.dumps(content,ensure_ascii=False)+'\n') # ensure_ascii=False ,显示中文,不然显示unicode编码
def main(offset):
url = 'https://maoyan.com/board/4?offset='+str(offset)
html = get_one_page(url)
for item in parse_one_page(html):
print(item)
write_to_file(item)
if __name__ == '__main__':
for i in range(10):
main(offset=i *10) # 调用一次就下一页
time.sleep(1)