python【反爬、xpath解析器、代理ip】
反爬、xpath解析器、代理ip
1.自动登录
1) requests自动登录
步骤:
第一步:人工对需要自动登录网页进行登录
第二步:获取这个网站登录后的cookie信息
第三步:发送请求的时候在请求中添加cookie值
#登录知乎
import requests
headers = {
'cookie':'_xsrf=p6x9UwvzRn32qWVoFyBaD4XEA8AGIEa3; _zap=19602ad1-626f-420a-ae86-9426c03f1721; Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49=1680319020; d_c0=ANBXognIjhaPTuFh6al-dhqCYaAaJS5kG08=|1680319019; gdxidpyhxdE=mLGLh6nWCUlW%2BkWJRMSOlbPgwJwEkGKvoLB%5CDwA88f1Gase4JRiL%5CNAO%2FwCKYTX51eDsxeCJTqGdqu4V2u3xOheyUMK2WIR8w%2Fqz0%2F3T9hU0NEkMGQeod60kUS8DuoOtAxu3U%2B%2Bur8%2Br%5CkmyJ5a6vbsZWmm8x6W%2BLIuMNWUV5Wol6eT3%3A1680319921123; YD00517437729195%3AWM_NI=Gk2NR%2Bvd2a7H5U28K9kTmYZGcGxv4i9vNkxHRdLwZzYjtebbmFCRe%2Fv%2BoIS1Yq07y5EJl9Rag0chkvLE1QyRbQeMfdVbvwnD0RviO%2F7yZq4B%2FlmL7Z1Ga4dqumsvVWwEOVk%3D; YD00517437729195%3AWM_NIKE=9ca17ae2e6ffcda170e2e6eebac54ab2f5a4a3bc4181b48ba3c55e839f8fb0d85cf4aa97daeb46f5aabba8f42af0fea7c3b92a85b5feafd121b6bcfe82b644f78bfed9ca33a98ca3bad94da199b897b763fbaa828cfb4492bc8498d9729bb6bc86e16aaf9a8db3e825b6f5a1aad23b9baf00d8fc3f8796a4dad16ba5f0ad89ea7e909bffb2fc5aa28fabaee57096beba98ed50f48eba8ace25f5a79692b74aedb4a3adb652f399afd5e77bb7b3bd97d55db59b81b7ea37e2a3; YD00517437729195%3AWM_TID=d8d4rn39BaFEFVBVFQKEKh6cplJ77qDq; Hm_lpvt_98beee57fd2ef70ccdd5ca52b9740c49=1680319035; captcha_session_v2=2|1:0|10:1680319034|18:captcha_session_v2|88:YXUydDJKQ1hyTWZ4SVlQeDNKQko4eTlQS2hBV210Q2I3MEEvaVh6TkhaNGNwTC9vc3ZVbXNrV05mUkR4UmdQbQ==|41309f72b1a177584d79526caefa60a33597e3e5623ef7f86eb98d82d937da5d; __snaker__id=Mbfbw4MqXaiZJqmI; captcha_ticket_v2=2|1:0|10:1680319288|17:captcha_ticket_v2|704:eyJ2YWxpZGF0ZSI6IkNOMzFfMTZSdVNwY0FwbDZMejVJSllWclVUU0J6eTgtRnVadENKc1Itay0wZEI1X2I2RlVmLXBEOXFudHF6RUJnNXUyMmN2Ny0xemdfNWVNaHVKaG9Va1ZCS0lDY2NldVM1cm5tUFBWaWwwZGtYOG5iNXN0c2UtT1NjRk9hd3lZN2hUZXQ2NkZweXdkcElPdXlxek5rQkc4Lm4xZFYwMDdQX29BRW44aWFpT3dJaW1XMTFsbDlCbjllUHZnc3RaeEM0ZUM2WUpES0R0dUpxLlNjNVBncGV2bGpqaHB5Z3FsZWR2cXd4cDBGUjdWZjJROU1rNXVDMDJCMTJPVEVsS0dJWUE2QUF1bVJ1VkVneTlmeEdmdDZ1dzZVV0tjaDRZWWt0LWloNzg3aEtYVkUyaHVLcHJ5TE04TkU4U1VDV21Sd2pLTDRZaXFwTlE4MjJvMHdmdzBBMDJWLnBILU50TnNyS3cudGJwYlkyWlhhbDI1MktZdEpNMVp0bWJTMW9MeFJGWDFjaUFSUHlpRi5vVU1tdHQ0ZUxzMURzUUdTTmJsSFZrbFJWRmRQWEhxbnktZU8ycGhubTRWaS5PaWhqMm51bng5WWdKVFNMRGQtbC5sQTV6d1ZZUDgwTlZWc3hSTW1LY3N5UmotOHpmUWw4cVhjbUp4akhiZmJIYi1fSnZpMyJ9|31c79c4cf61774a15336dbd47264e24052e90e278c7b7ad326a7f771283e2674; z_c0=2|1:0|10:1680319303|4:z_c0|92:Mi4xNFRCVEN3QUFBQUFBMEZlaUNjaU9GaVlBQUFCZ0FsVk5SX0VVWlFBYlBJY1djM1g4enhnQm9RTHE4NjlJcGJnaTFn|d67d02d7c6c6adbb7386ef1e5112961db215d79ee7f9c5b7dcbda1922dbcdb20; q_c1=3557e163dacf470885650132315f9a99|1680319303000|1680319303000; tst=r; KLBRSID=2177cbf908056c6654e972f5ddc96dc2|1680319315|1680319018'
,
"user-agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'}
response = requests.get('https://www.zhihu.com/signin?next=%2F')
print(response.text)
2)selenium获取cookie
# 淘宝自动登录
from selenium.webdriver import Chrome
# 1.创建浏览器打开需要自动登录的网站
b = Chrome()
b.get('https://www.taobao.com')
# 2.留足够长的时候,人工完成登录(必须得保证b指向的窗口的网页中能看到登录以后的信息)
input('是否已经完成登录:')
# 3.获取登录成功后的cookie信息,保存到本地文件
result = b.get_cookies()
# print(result)
# 4.保存cookie到文件
with open('files/淘宝cookie.txt', 'w', encoding='utf-8', newline='') as f:
f.write(str(result))
print('___________结束__________')
3) 使用selenuim获取得到的cookie
from selenium.webdriver import Chrome
# 1.创建浏览器打开需要自动登录的网站
b = Chrome()
b.get('https://www.taobao.com')
# 2.获取本地爆存的cookie
with open('files/淘宝cookie.txt', encoding='utf-8') as f:
result = eval(f.read())
# 3.添加cookie
for x in result:
b.add_cookie(x)
# 4.重新打开网页
b.get('https://www.taobao.com')
input('end:')
2.代理ip
处理已经被封了的ip地址,代理ip是用的极光ip,百度搜索就有了,买一个就可以操作了
1)requests代理
import requests
headers = {
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36'
}
# 在这里我使用的是代理ip
proxies = {
'https': '114.238.85.97:4515'
}
# 使用代理ip发送请求
res = requests.get('https://movie.douban.com/top250?start=0&filter=', headers=headers, proxies=proxies)
print(res.text)
2)selenium代理
from selenium.webdriver import Chrome,ChromeOptions
options = ChromeOptions()
# 设置代理
options.add_argument('--proxy-server=http://114.238.85.97:4515')
b=Chrome(options=options)
b.get('https://movie.douban.com/top250?start=0&filter=')
input()
3.xpath解析器
import json可以将json数据直接转换成python数据
xpath是用来解析网页数据或者xml数据的一种解析方法,他是通过路径来获取标签(元素)
python数据;{‘name’:‘lily’,‘age’:18,‘is_ad’:‘True’}
json数据:{‘name’:lily,‘age’:18,‘is_ad’:true,‘car’:null}
xml数据:
lily
18
<is_ad>是</is_ad>
<car_no></car_no>
1)常见的几个概念
树:整个网页结构和xlml结构就是一个树结构
元素(节点):html树结构的每个标签
根节点:树结构中的第一个节点
内容:标签内容
属性:标签属性
2) xpath语法
1.获取标签
1)绝对路径:以/开头,从根节点开始层层往下写路径
2)相对路径:写路径的时候用’.‘或者’..‘开头,其中’.‘表示当前节点;’..‘表示当前节点的父节点
注意:如果路径以./开头,./可以省略
3)全路径:
2.获取标签内容
在获取标签的路径的最后加’/text()‘
3.获取标签属性
在获取标签的路径的最后加’/@属性名‘
4.案例
首先导入包
from lxml import etree
1.创建树结构,获取根节点
html = open('data.html', encoding='utf-8').read()
root = etree.HTML(html)
2.通过路径获取标签
节点对象.xpath(路径) —— 根据路径获取所有的标签,返回值是列表,列表中的元素是节点对象
1) 绝对路径
result = root.xpath('/html/body/div/a')
print(result)
2)获取标签内容
result = root.xpath('/html/body/div/a/text()')
print(result)
3) 获取标签属性
result = root.xpath('/html/body/div/a/@href')
print(result)
4)绝对路径的写法跟xpath前面用谁去点的无关
div = root.xpath('/html/body/div')[0]
result = div.xpath('/html/body/div/a/text()')
print(result)
5)相对路径
result = root.xpath('./body/div/a/text()')
print(result)
result = div.xpath('a/text()')
print(result)
6)全路径
result = root.xpath('//a/text()')
print(result)
result = root.xpath('//div/a/text()')
print(result)
3.加谓语(加条件)—— 路径中的节点[]
1)位置相关谓语
[N] —— 第N个指定标签
[last()] —— 最后一个指定标签
[last()-N] —— 获取倒数指定标签
[position()>N]、[position()>=N]、[position()<N]、[position()<=N]、假如总共有5个,N=3,那就获取第4和第5个
result = root.xpath('//span/p[2]/text()')
print(result)
2) 获取p标签最后一个标签
result = root.xpath('//span/p[last()]/text()')
print(result)
result = root.xpath('//span/p[position()>2]/text()')
print(result)
3)属性相关谓语
[@属性名=属性值]
result = root.xpath('//span/p[@id="p1"]/text()')
print(result)
result = root.xpath('//span/p[@class="c1"]/text()')
print(result)
result = root.xpath('//span/p[@data="5"]/text()')
print(result)
4.通配符
在xpath中可以通过*表示任意标签或者任意属性
result = root.xpath('//span/*/text()')
print(result)
result = root.xpath('//span/*[@class="c1"]/text()')
print(result)
result = root.xpath('//span/span/@*')
print(result)
将整个网页的所有的class=c1的标签全部取到
result = root.xpath('//*[@class="c1"]/text()')
print(result)
3)案例:
成都链家二手房数据
1.分行政区爬取所需信息。
2.确定信息所在位置(ul > li)
3.确定使用的方法:requests > selenium
4.确定使用的解析器:正则表达式 > xpath > bs4
5.确定网站反扒机制,根据对应机制采取对应措施(反反爬虫)
6.爬取单页信息
7.根据网站规则爬取多页信息
8.数据持久化(将数据保存:表格、数据库......)
import requests
from bs4 import BeautifulSoup
import json
import csv
from tqdm import tqdm
import os
# 创建请求函数
def get_requests(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.30'
}
resp = requests.get(url=url, headers=headers)
if resp.status_code == 200:
soup = BeautifulSoup(resp.text, 'lxml')
return soup
else:
print(resp.status_code)
# 获取行政区名和链接的函数
def country(html_code):
# 获取行政区所在a标签
a_list = html_code.select(
'body > div:nth-child(12) > div > div.position > dl:nth-child(2) > dd > div:nth-child(1) > div > a')
# print(a_list)
dict_1 = {}
for i in a_list:
# 行政区名
name = i.text
# 链接
href = 'https://cd.lianjia.com' + i.attrs['href']
# print(name, href)
dict_1[name] = href
return dict_1
# 获取每个行政区二手房总页数
def get_page_num(html_code):
page_dict = html_code.select_one(
'#content > div.leftContent > div.contentBottom.clear > div.page-box.fr > div').attrs['page-data']
# print(page_dict)
# 将字符串类型的字典转回字典,并且将总页数提取出来
num = json.loads(page_dict)['totalPage']
return num
# 创建主函数
def main(url):
# 请求链家二手房链接
code_1 = get_requests(url)
# print(code_1)
# 调用获取country()函数
country_dict = country(code_1)
# print(country_dict)
for key, value in country_dict.items():
# print(key, value)
# 请求行政区链接
code_2 = get_requests(value)
# print(code_2)
# 调用get_page_num函数
total_page = get_page_num(code_2)
# print(total_page)
# 数据持久化
f = open(f'数据/成都{key}二手房信息.csv', 'w', encoding='utf-8', newline='')
# 创建CSV写方法
mywrite = csv.writer(f)
# 列名
col_name = ['行政区', '标题', '小区', '街道', '户型', '面积', '装修', '单价', '总价']
mywrite.writerow(col_name)
for i in tqdm(range(1, total_page + 1), desc=key):
# 拼接有页数的链接
new_href = value + f'pg{i}/'
# print(new_href)
html_code = get_requests(new_href)
li_list = html_code.select('#content > div.leftContent > ul > li > div.info.clear')
# print(li_list, len(li_list))
for i in li_list:
# print(i)
# 房屋标题
title = i.select_one('div.info.clear > div.title > a').text
# 地址
address_1 = i.select_one('div.info.clear > div.flood > div > a:nth-child(2)').text
address_2 = i.select_one('div.info.clear > div.flood > div > a:nth-child(3)').text
# 基本信息
info = i.select_one('div.info.clear > div.address > div').text
info_list = info.split('|')
# 户型
type = info_list[0].strip()
# 面积
area = info_list[1].strip()
# 装修
decorate = info_list[3].strip()
# 单价
unit_price = i.select_one('div.info.clear > div.priceInfo > div.unitPrice > span').text
# 总价
total_price = i.select_one('div.info.clear > div.priceInfo > div.totalPrice.totalPrice2 > span').text
# print(key, title, address_1, address_2, type, area, decorate, unit_price, total_price)
data = [key, title, address_1, address_2, type, area, decorate, unit_price, total_price]
mywrite.writerow(data)
f.close()
# 程序从此处开始执行
URL = 'https://cd.lianjia.com/ershoufang/rs/'
# 判断数据文件夹是否存在
if os.path.exists('数据'):
main(URL)
else:
os.mkdir('数据')
main(URL)