1 学习网络爬虫
所有可以在网上看到的数据都可以通过爬虫程序保存。
Robots网络爬虫排除标准设计网络爬虫排除标准Robots协议告诉搜索引擎哪些页面可以爬取,哪些页面不可以爬取。
2 网络爬虫的基本问题
-
Python爬虫的过程是什么? 1.获取网页 2.分析网页(提取数据)3.存储数据
-
三个过程的技术实现是什么? 1.获取网页 获取网页的基本技术:request、urllib和selenium(模拟浏览器) 获取网页的先进技术:多线程多线程抓取、登录抓取、突破IP封禁和服务器抓取。 2.解析网页 分析网页的基本技术:re正则表达式,BeautifulSoup和lxml。 分析网页的先进技术:解决中文乱码 3.存储数据 存储数据的基本技术:txt文件和存入csv文件 存储数据的先进技术:存储数据MySQL数据库和存入MongoDB数据库。
3 编写第一个网络爬虫
写第一个爬虫
首先,自行安装Anaconda。我们会用它自带的Jupiter编写网络爬虫。 爬网站为www.santostang.com”,为《Python作者从入门到实践的博客,感谢作者给我们带来了这么好的作品。 首先,让我们来看看一个简单的爬虫程序。 第一步,获取页面
import requests link = "http://www.santostang.com/" headers = {
'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Fierfox/3.5.6'} r = requests.get(link, headers= headers) print(r.text)
用request的headers伪装成浏览器访问。 第二步是提取数据
import requests from bs4 import BeautifulSoup link = "http://www.santostang.com/" headers = {
'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Fierfox/3.5.6'} r = requests.get(link, headers= headers) soup = BeautifulSoup(r.text, "lxml") title = soup.find("h1", class_="post-title").a.text.strip() print (title)
提取的数据如下:
第四章 – 4.3 通过selenium 抓取模拟浏览器
第三步:存储数据
import requests from bs4 import BeautifulSoup link = "http://www.santostang.com/" headers = {
'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Fierfox/3.5.6'} r = requests.get(link, headers= headers)
soup = BeautifulSoup(r.text, "lxml")
title = soup.find("h1", class_="post-title").a.text.strip()
print (title)
with open('title1.txt',"a+") as f:
f.write(title)
f.close()
Python 基础试题
试题1:请使用Python中的循环打印输出从1到100的所有的奇数。
for i in range(1, 101):
if i % 2:
print(str(i) + " ",end='')
试题2 :请将字符串’你好$$$我正在学Python@####现在需要&%&%&%修改字符串’中的符号换为空格。
str1 = '你好$$$我正在学Python@####现在需要&%&%&%修改字符串'
str2 = str1.replace('$$$', ' ').replace('@####', ' ').replace('&%&%&%', ' ')
print(str2)
试题3:输出 9 × 9 9 \times 9 9×9乘法口诀表。
for i in range(1, 10):
for j in range(1, i + 1):
print(str(i) + '*' + str(j) + ' ', end = '')
print()
试题4:请写出一个函数,当输入函数变量月利润为I时,能返回应发放奖金的总数。例如,输出“利润为100000元时,应发放奖金总数为10000元”其中,企业发放的奖金根据利润提成。利润D 低于或等于10万元时,奖金可提10%;利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%;利润在20万元到40万元之间时,高于20万元的部分可提成5%;利润在40万元到60万元之间时,高于40万元的部分可提成3%;利润在 60 万元到 100 万元之时,高于60万元的部分可提成1.5%;利润高于100万元时,超过100万元的部分按1%提成。
def calcute_profit(I):
I = I / 10000
if I <= 10:
a = I * 0.01
return a * 10000
elif I <= 20 and I > 10:
b = 0.25 + I * 0.075
return b * 10000
elif I <= 40 and I > 20:
c = 0.75 + I * 0.05
return c * 10000
elif I <= 60 and I > 40:
d = 0.95 + I * 0.03
return d * 10000
elif I <= 60 and I > 100:
e = 2 + I * 0.015
return e * 10000
else:
f = 2.95 + I * 0.01
return f * 1000
I = int(input('净利润:'))
profit = calcute_profit(I)
print ('利润为%d元时,应发奖金总数为%d元' % (I, profit))
试题5:用字典的值对字典进行排序,将{1:2,3:4,4:3,2:1,0:0}按照字典的值从小到大排列。
import operator
x = {
1:2,3:4,4:3,2:1,0:0}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))
print(sorted_x)
试题6:请问以下两段代码的输出分别是什么?
a = 1
def fun(a):
a = 2
fun(a)
print (a)
答案:输出1
a = []
def fun(a):
a.ppend(1)
fun(a)
print (a)
答案:输出 1 试题7:请问一下两段代码的输出分别是什么?
class Person:
name = "aaa"
p1 = Person()
p2 = Person()
p1.name = "bbb"
print (p1.name)
print (p2.name)
print (Person.name)
bbb aaa aaa
class Person:
name = []
p1 = Person()
p2 = Person()
p1.name.append(1)
print (p1.name)
print (p2.name)
print (Person.name)
[1] [1] [1]
4 静态网页抓取
需要安装request库,还请读者自行安装。
4.1 获取相应内容
在request中,最常用的功能是获取某个网页的内容。现在我们使用 request获取个人博客主页的内容。
import requests
r = requests.get('http://www.santostang.com/')
print ("文本编码:", r.encoding)
print ("响应状态码:", r.status_code)
print ("字符串方式的响应体:", r.text)
上例的说明如下: (1)r.text是服务器响应的内容,会自动根据响应头部的字符编码进行解码。 (2)r.encoding是服务器内容使用的文本编码。 (3)r.status_code用于检测响应的状态码;返回5xx则表示服务期错误响应。我们可以用r.status_code来检测请求是否正确响应。 (4)r. content 是字节方式的响应体,会自动解码gzip和deflate编码的响应数据。 (5)r.json()是request中内置的JSON解码器。
4.2 定制requests
有些网页需要定制requests的参数才能获取需要的数据,包括传递URL参数、定制请求头、发送POST请求、设置超时等。
4.2.1 传递URL参数
往往以字典的形式传递参数。
import requests
key_dict = {
'key1':'value1','key2':'value2'}
r = requests.get('http://httpbin.org/get', params=key_dict)
print ("URL已经正确的编码:", r.url)
print ("字符串方式的响应体:\n", r.text)
URL已经正确的编码: http://httpbin.org/get?key1=value1&key2=value2 字符串方式的响应体: { “args”: { “key1”: “value1”, “key2”: “value2” }, “headers”: { “Accept”: “/”, “Accept-Encoding”: “gzip, deflate”, “Host”: “httpbin.org”, “User-Agent”: “python-requests/2.25.1”, “X-Amzn-Trace-Id”: “Root=1-6270f40e-0afeada86d2efeab067bc977” }, “origin”: “112.38.217.11”, “url”: “http://httpbin.org/get?key1=value1&key2=value2” }
4.2.2 定制请求头
查看请求头的信息:
GET / HTTP/1.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 Cache-Control: max-age=0 Connection: keep-alive Cookie: PHPSESSID=ajfv5ma4f58pe1on1hbff1na01 Host: www.santostang.com Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36 Edg/101.0.1210.32
提取请求头中重要的部分,可以把代码写成;
import requests
headers = {
'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36 Edg/101.0.1210.32',
'Host':'www.santostang.com'
}
r = requests.get('http://www.santostang.com/',headers= headers)
print ("响应状态码:",r.status_code)
4.2.3 发送POST请求
除了GET请求外,有时还需要发送一些编码为表单形式的数据,比如说登录的时候请求就为POST,因为如果用GET请求,密码就会显示在URL中,安全性极低。如果要实现POST请求,只需要简单地传递一个字典给request中的data参数,这个数据字典就会在发出请求的时候自动编码为表单形式。
import requests
key_dict = {
'key1':'value1','key':'value2'}
r = requests.post('http://httpbin.org/post',data=key_dict)
print (r.text)
{ “args”: {}, “data”: “”, “files”: {}, “form”: { “key”: “value2”, “key1”: “value1” }, “headers”: { “Accept”: “/”, “Accept-Encoding”: “gzip, deflate”, “Content-Length”: “22”, “Content-Type”: “application/x-www-form-urlencoded”, “Host”: “httpbin.org”, “User-Agent”: “python-requests/2.25.1”, “X-Amzn-Trace-Id”: “Root=1-627107a1-6044b25d30954b6b30272954” }, “json”: null, “origin”: “112.38.217.11”, “url”: “http://httpbin.org/post” }
可以看到,form 变量的值为 key_dict 输入的值,这样一个 POST 请求就发送成功了。
4.2.4 超时
意思就是,如果服务器在 timeout 秒内没有应答,就返回异常。 将timeout设置为0.001试一下
import requests
link = "http://www.santostang.com/"
r = requests.get(link, timeout= 0.001)
返回的异常为:
ConnectTimeout: HTTPConnectionPool(host=‘www.santostang.com’, port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x000001E27188FBB0>, ‘Connection to www.santostang.com timed out. (connect timeout=0.001)’))
异常值的意思为,时间限制在0.001秒内,连接到地址为 www.santostang.com 的时间已到。
5 动态网页抓取
如果使用AJAX加载的动态网页,爬取里面动态加载的内容的方法有二: (1)通过浏览器审查元素解析地址。 (2)通过Selenium模拟浏览器抓取。
5.1 通过浏览器审查元素解析地址
import requests
link = """https://api-zero.livere.com/v1/comments/list?callback=jQuery1124029565129817049396_1651637402392&limit=10&repSeq=4272904&requestPath=%2Fv1%2Fcomments%2Flist&consumerSeq=1020&livereSeq=28583&smartloginSeq=5154&code=&_=1651637402394"""
headers = {
'Host':'api-zero.livere.com',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36'
}
r = requests.get(link,headers= headers)
print (r.text)
结果:
综上所述,如果要爬取类似淘宝网评论这种用AJAX加载的网页的话,从网页源代码中是找不到想要的数据的。需要用浏览器的审查元素,找到真实的数据地址。然后爬取真实的网站。 爬取评论内容;
import json
json_string = r.text
json_string = json_string[json_string.find('{'):-2]
json_data = json.loads(json_string)
comment_list = json_data['results']['parents']
for eachone in comment_list:
message = eachone['content']
print (message)
运行结果为:
爬取多页: (现在爬不了了,URL的变换规律换了)
import requests
import json
def single_page_comment(link):
headers = {
'Host':'api-zero.livere.com',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36'
}
# 获取 json 的string
json_string = r.text
json_string = json_string[json_string.find('{'):-2]
json_data = json.loads(json_string)
comment_list = json_data['results']['parents']
for eachone in comment_list:
message = eachone['content']
print (message)
for page in range(0,4):
link1 = "https://api-zero.livere.com/v1/comments/list?callback=jQuery112403473268296510956_1531502963311&limit=10&offset="
link2 = "&repSeq=4272904&requestPath=%2Fv1%2Fcomments%2Flist&consumerSeq=1020&livereSeq=28583&smartloginSeq=5154&_=1531502963316"
page_str = str(page)
link = link1 + page_str + link2
print (link)
single_page_comment(link)
5.2通过selenium模拟浏览器抓取
在上述的例子中,使用Chrome“检查”功能找到源地址还十分容易。但是有一些网站非常复杂,例如前面的天猫产品评论,使用“检查”功能很难找到调用的网页地址。除此之外,有一些数据真实地址的URL也十分冗长和复杂,有些网站为了规避这些抓取会对地址进行加密,造成其中的一些变量让人摸不着头脑。 首先,安装 selenium。 我们使用selenium打开一个浏览器和一个网页:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("http://www.baidu.top")