爬虫案例(某某二手房)
步骤
- 请求模块
# 封装一个函数,用于将url处理成请求对象
def request_by(url,city,page):
page_url = url%(city,page)
# 请求头
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
return request.Request(url=page_url,headers=headers)
# 封装一个函数,用于发起请求
def request_data(url,city_list):
# 对citylist进行遍历
for city in city_list:
# 每个城市遍历100页
for page in range(1,4):
# 创建每个页面的请求对象
req = request_by(url=url,city=city,page=page)
# 发请求
res = request.urlopen(req)
print("正在请求城市%s的第%d页"%(city,page))
sleep(1)
yield res.read().decode("utf-8")
- 解析模块
def analysis_data(data):
for html in data:
# 创建一个节点树
html_tree = etree.HTML(html) # 这个函数用于将html字符串转化成html节点树
# 解析出每一个房屋单元
house_list = html_tree.xpath("//ul[@class='sellListContent']/li")
for house in house_list:
# 创建一个字典用于整合每一个房源的信息
item = {}
# title
item["title"] = house.xpath(".//div[@class='title']/a/text()")[0]
# 位置
item["position"] = "".join(house.xpath(".//div[@class='positionInfo']//text()"))
# 房屋信息
item["houseInfo"] = "".join(house.xpath(".//div[@class='houseInfo']//text()"))
# 单价
item["unitPrice"] = re.findall(pattern=r'[0-9]*',string=house.xpath(".//div[@class='unitPrice']/span/text()")[0])[2]
# 总价
item["totalPrice"] = house.xpath(".//div[@class='totalPrice']/span/text()")[0]
yield item
# print(item)
- redis存储模块
def write_to_redis(data):
# 创建一个redis链接
rds = redis.StrictRedis(host="**********",port=6379,db=1)
# 向redis数据库中存入数据
for item in data:
rds.lpush("ershoufang",json.dumps(item)) # 某些版本的redis数据库不能直接存字典和对象,必须把字典转成json字符串
- 调用函数
if __name__ == '__main__':
url = 'https://%s.******.com/ershoufang/pg%d/'
# 生成一个城市列表
city_list = ['sh','sz','gz','hz','tj']
html_list = request_data(url=url,city_list=city_list)
house_list = analysis_data(html_list)
write_to_redis(house_list)
requests 模块
- requests是一个第三方的请求框架,对urllib进行了二次的封装,简化urllib的一些操作
简单的get请求
res = requests.get(url="https://www.baidu.com")
print(res) #<Response [200]>
print(res.text) # 字符串格式的响应体
print(res.content) # 二进制格式的响应体
带参的get请求
url = "https://www.baidu.com/s"
# 请求体
params = {
"ie":"utf-8",
"wd":"范冰冰"
}
# 请求头
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
res = requests.get(url=url,params=params,headers=headers)
print(res)
post请求
post_url = "https://fanyi.baidu.com/sug"
# 请求体
data = {
"kw":"a"
}
res = requests.post(url=post_url,data=data,headers=headers)
print(res.text)
会话处理
-
为什么引进会话技术?
requests没有直接接收cookie的功能,
由于requests不能直接接收cookie,此时再次发请求时并没有携带cookie,后台就检测不到登录信息,就会跳转至登录页
-
使用session的原因
- 用Session对象发起请求,不仅可以提交参数还能提交cookie
- 用Session对象来发起请求,不仅可以接收响应体还能接收cookie
-
使用方法
import requests
login_url = 'http://www.jokeji.cn/user/c.asp'
# u=112&p=qweqe&sn=1&t=big
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
# 创建一个requests的Session对象,用于接收并保存cookie
s = requests.Session()
params = {
"u":"*****",
"p":"*******",
"sn":"1",
"t":"big"
}
# 发起get请求来登录
res = s.get(url=login_url,params=params,headers=headers)
print(res.text)
# 跳转主页url
main_url = "http://www.jokeji.cn/User/MemberJoke.asp"
main = s.get(url=main_url,headers=headers)
print(main.text)
使用requests爬取某网站
- 分析该网页登录页面需要提供什么信息?
- 需要提交验证码和两个token值,而这两个token值和验证码都是通过刷新登录页得到的,所以我们在向登录接口发post请求之前首先要想当前的这个登录页面的url发起一个get请求来提取以上信息
- 登录页的get请求应该用requests来发还用Session?
- 请求的时候要用Session,因为验证码和token获取要和当前终端cookie对应上
操作流程
# 创建一个Session对象
s = requests.Session()
# 登录页面url
login_page = 'https://so.**.org/user/login.aspx?from=http://so.**.org/user/collect.aspx'
# 访问登录页面来提取验证码和token
login_html = s.get(url=login_page,headers=headers)
# 提取token
login_tree = etree.HTML(login_html.text)
token1 = login_tree.xpath("//input[@id='__VIEWSTATE']/@value")[0]
token2 = login_tree.xpath("//input[@id='__VIEWSTATEGENERATOR']/@value")[0]
# 提取验证码(拼接域名和路由)
code_url = "https://so.*****.org" + login_tree.xpath("//img[@id='imgCode']/@src")[0]
# 下载验证码,下载验证码的时候也要用Session
code_data = s.get(code_url,headers=headers)
with open("code.png","wb") as fp:
fp.write(code_data.content)
# print(token1,token2)
# 人工识别验证码
code = input("请打开验证码图片查看,并且在此处输入你看到的内容:")
# 发起post请求登录
login_url = "https://so.*****.org/user/login.aspx?from=http%3a%2f%2fso.****.org%2fuser%2fcollect.aspx"
data = {
'__VIEWSTATE': token1,
'__VIEWSTATEGENERATOR':token2,
'from': 'http://so.***.org/user/collect.aspx',
'email':'*****',
'pwd':'*******',
'code':code,
'denglu':'登录'
}
res = s.post(url=login_url,data=data,headers=headers)
print(res.text)