最近学完了python,老师让我们用爬虫的知识去爬取ZOJ里面的题目信息。花了一段时间,顺利的解决了遇到的许多问题,嘻嘻。
**
一、需要的包
**
requsets、re、BeautifulSoup、json、csv。
requests的作用主要是获取页面上的一些资源,我们对这些资源进行处理。就好像是用代码来访问浏览器一样。这里借用百度百科的介绍
Request对象的作用是与客户端交互,收集客户端的Form、Cookies、超链接,或者收集服务器端的环境变量。request对象是从客户端向服务器发出请求,包括用户提交的信息以及客户端的一些信息。客户端可通过HTML表单或在网页地址后面提供参数的方法提交数据,然后服务器通过request对象的相关方法来获取这些数据。request的各种方法主要用来处理客户端浏览器提交的请求中的各项参数和选项。
re库就是用来字符匹配,选出需要的内容。我们用requests得到的信息通常带有各种各样的字符,但真正是我们所需要的只是一部分,这时我们就可以采用re来进行切片。这里就要求使用正则表达式,我们可以在正则表达式的在线测试中进行测试。
BeautifulSoup是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据,就是可以将标签语言给去掉。
json可以将获得的信息转变为字典类型。
csv可以将获得的数据用csv的表格形式存储。
**
二、分析爬取方式
**
不同的网站,他们的反爬虫措施是不一样的。例如像热搜,它就属于没有反爬机制,可以直接用requests.get(URL)的方式获得信息,然后再用BeautifulSoup解析,再用re.findall()找到自己需要的信息。这样就可以获得热搜榜上的信息。这属于最简单的方式。
例如我们所爬取的ZOJ它属于动态网站,网页上没有相关的信息,必须要二次加载在服务器端运行后将数据传输上来。如果我们采用刚才的方法,我们就只能获得它的标签,不能获得数据。如果遇到这样的情况我们就需要去找相应的json文件。
右键页面查看元素
选择网络
然后一个个的去浏览主要是看参数和响应
这里就发现了最后一个文件保存着我们要爬取的信息。由于我们json文件是需要二次加载的,也就是浏览器要向服务器发出请求才能获取这些数据,所以我们再用requests时,要加入课外的请求头
将这些信息存入你所写的请求头。
这样就可以获得你所需要的信息了,接下来就是对他们进行切片和用csv格式保存下来。
小插曲:在编写爬虫的时候,我爬的是火狐,他让我遇到了400、403、406的错误,让我百思不得其解。最后如何解决的呢?。。。我换成了chrome,一下就成功。
**
以下是我的代码和运行后的结果
**
import requests
import re
import json
import csv
headers = {
"Accept":"application/json;charset=UTF-8",
"Accept-Encoding": "gzip,deflate,br",
"Accept-Language": "en-US",
"Connection":"keep-alive",
'Cache-Control': 'max-age=0',
"Content-Type": "application/json;charset=UTF-8",
"Cookie":'JSESSIONID=1E829B79BA93DE2D5F4FFD3996A6E619',
"Host": "zoj.pintia.cn",
"Referer": 'https://zoj.pintia.cn/problem-sets/91827364500/problems',
"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537'
'.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36',
"X-Lollipop": '6f0306a4126bd9ad8899c3cb5d652ab8',
"X-Marshmallow": '174591203%-1220526426'
}
f=open('D:\\ZOJ.csv','w')
csv_W=csv.writer(f)
csv_W.writerow(["id","label","score","deadline","acceptCount","submitCount","title","type"])
page=0
try:
while True:
url='https://zoj.pintia.cn/api/problem-sets/91827364500/problem-list?exam_id=0&page='+str(page)+'&limit=100&problem_type=PROGRAMMING'
html = requests.get(url,headers=headers)
html_info=re.findall('\{.*\}',html.text)[0]
bk = json.loads(html_info)
dic={}
m=0
for i in bk["problemSetProblems"]:
id=bk["problemSetProblems"][m]["id"]
label=bk["problemSetProblems"][m]["label"]
score=bk["problemSetProblems"][m]["score"]
deadline=bk["problemSetProblems"][m]["deadline"]
acceptCount=bk["problemSetProblems"][m]["acceptCount"]
submitCount=bk["problemSetProblems"][m]["submitCount"]
title=bk["problemSetProblems"][m]["title"]
type=bk["problemSetProblems"][m]["type"]
csv_W.writerow([id,label,score,deadline,acceptCount,submitCount,title,type])
m=m+1
page=page+1
except:
print("完成")
f.close()
可以根据需求的不同,获取不同的信息。
另外每一个用户关于请求头的内容都是不相同的哦!
不同的网站反爬虫机制都不相同,我们需要根据实际情况,来制定解决方案。下一个爬虫我想写一个爬取每一个题目下面的内容。加油,奥力给!