爬虫工具
python3 pycharm edge/chrome
requests库的用法
requests库是python中简单易用的HTTP库
用命令行安装第三方库 pip install requests
导入库import requests
获取响应内容
import requests
r = requests.get('http://www.baidu.com/')
print("文本编码:", r.encoding) # ISO-8859-1
print("响应状态码:", r.status_code)
# print ("字符串方式的响应体:", r.text)
# 响应体乱码解决
print("字符串方式的响应体:", r.text.encode('ISO-8859-1'))
xpath的用法
xpath可以在XML文档中查找信息,在XML中通过元素和属性进行定位
常用的表达式
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 从根节点选取(取子节点)。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点 |
… | 选取当前节点的父节点 |
@ | 选取属性 |
谓语
路径表达式 | |
---|---|
//table/tbody/tr | table标签下的tbody标签下的所有tr节点 |
//a/@src | 选取a标签下的src属性 |
//div[@class=“box”] | 选取class="box"的div节点 |
使用lxml解析
安装pip install lxml
导入库from lxml import etree
lxml
将_html_文本转换为_xml_对象
实例化一个**etree**
对象,且将解析的源码加载到该对象中
tree = etree.HTML(html)
# result = etree.tostring(tree) 补全html的基本写法
# 比如补全缺少的结束标签
xpath中的 text(), string(), data()的区别如下:
text()
仅仅返回所指元素的文本内容string()
函数会得到所指元素的所有节点文本内容,这些文本会被拼接成一个字符串.data()
大多数时候和string()通用不建议经常使用.(可能会影响性能)
基本使用
from lxml import etree
wb_data = """
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</ul>
</div>
"""
html = etree.HTML(wb_data)
print(html)
result = etree.tostring(html)
print(result.decode("utf-8"))
输出
<Element html at 0x1cf63c799c8>
<html><body><div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</li></ul>
</div>
</body></html>
用.text
和/text()
获取某个标签内容
# html = etree.HTML(wb_data)
# html_data = html.xpath('/html/body/div/ul/li/a')
# for i in html_data:
# print(i.text)
html_data = html.xpath('/html/body/div/ul/li/a/@href')
# 或者 html_data = html.xpath('//li/a//@href')
for i in html_data:
print(i)
爬取ip网站
简单爬取ip
对ip代理网站ip3366.net
发起网络请求
import requests # 不要忘记导入库
from lxml import etree
url = 'http://www.ip3366.net/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'
} # headers是解决requests请求反爬的方法之一,伪装成浏览器
response = requests.get(url, headers=headers)
print(response.text)
发现是乱码,我们可以用print(response.encoding)
打印出这个网站的编码是ISO-8859-1
,所以我们用encode('_编码方式_')
将我们爬取到的HTML改成这个编码
page_text = response.text.encode('ISO-8859-1')
创建etree
实例对象用于解析HTML源码,并找到定位ip节点的位置
page_text = response.text.encode('ISO-8859-1')
tree = etree.HTML(page_text)
tr_list = tree.xpath('//*[@id="list"]/table/tbody/tr') # tr的XML的列表
print(tr_list)
ip_list = []
for tr in tr_list:
ip = tr.xpath('./td')[0].text + ':' + tr.xpath('./td')[1].text
# 通过HTML源码看出ip和port的在td的第一个和第二个所以定位索引0,1的文本
ip_list.append(ip) #list.append(x) 将x加入list尾
print(ip_list)
输出:
[<Element tr at 0x1f887077d40>, <Element tr at 0x1f887077d00>, <Element tr at 0x1f887077cc0>, <Element tr at 0x1f887057e80>, <Element tr at 0x1f887057f80>, <Element tr at 0x1f8870a3800>, <Element tr at 0x1f8870a3d40>, <Element tr at 0x1f8870a3880>, <Element tr at 0x1f88709ac80>, <Element tr at 0x1f8870a3a00>]
['113.252.11.250:8118', '103.143.196.50:8080', '115.218.4.39:9000', '27.159.188.239:3256', '115.218.0.13:9000', '118.114.110.231:8060', '103.82.170.211:808', '27.159.188.243:3256', '115.218.1.249:9000', '106.14.244.92:8080']
完整代码
# -*- coding = utf-8 -*- 默认utf-8的编码
import requests
from lxml import etree
url = 'http://www.ip3366.net/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'
} # headers是解决requests请求反爬的方法之一,伪装成浏览器
response = requests.get(url, headers=headers)
page_text = response.text.encode('ISO-8859-1')
tree = etree.HTML(page_text)
tr_list = tree.xpath('//*[@id="list"]/table/tbody/tr') # tr的XML列表
print(tr_list)
ip_list = []
for tr in tr_list:
ip = tr.xpath('./td')[0].text + ':' + tr.xpath('./td')[1].text
ip_list.append(ip)
print(ip_list)
筛选ip
-我们向一个正常网站发起请求测试ip是否可用,不可用就在列表中删除
(我这个移除方法可能效率很低)
for i in ip_list:
try:
r = requests.get('http://2021.ip138.com/', headers=headers, proxies={"http": i}, timeout=2)
if r.status_code == 200:
pass
else:
ip_list.remove(i)
except:
ip_list.remove(i)
-我们从网站页面和HTML源码可以看出网站提供了每个代理ip的响应速度,我可以在存ip代理之前判断ip的响应速度再存。
for tr in tr_list:
tr_time = tr.xpath('./td')[6].text
tr_time = tr_time.replace('秒', '')
if float(tr_time) <= 2:
ip = tr.xpath('./td')[0].text + ':' + tr.xpath('./td')[1].text
ip_list.append(ip)
爬取多个页面
[http://www.ip3366.net/?stype=1&page=1](http://www.ip3366.net/?stype=1&page=1)
第一页
[http://www.ip3366.net/?stype=1&page=2](http://www.ip3366.net/?stype=1&page=2)
第二页
[http://www.ip3366.net/?stype=1&page=5](http://www.ip3366.net/?stype=1&page=5)
第五页
通过观察每一页的网址我们可以发现传的page值就是页数的值
所以我们可以根据这个规律爬取多个网站
for page in range(1, 5):
url = 'http://www.ip3366.net/?page={}'.format(page)
response = requests.get(url, headers=headers)
完整的代码:
import requests
from lxml import etree
def get_ip():
ip_list = []
tr_list = []
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'
}
for page in range(1, 5):
url = 'http://www.ip3366.net/?page={}'.format(page)
response = requests.get(url, headers=headers)
page_text = response.text.encode('ISO-8859-1')
tree = etree.HTML(page_text)
tr_list = tree.xpath('//*[@id="list"]/table/tbody/tr')
for tr in tr_list:
tr_time = tr.xpath('./td')[6].text
tr_time = tr_time.replace('秒', '')
if float(tr_time) <= 2:
ip = tr.xpath('./td')[0].text + ':' + tr.xpath('./td')[1].text
ip_list.append(ip)
for i in ip_list:
try:
r = requests.get('http://2021.ip138.com/', headers=headers, proxies={"http": i}, timeout=2)
if r.status_code == 200:
pass
else:
ip_list.remove(i)
except:
ip_list.remove(i)
print(ip_list)
if __name__ == '__main__':
get_ip()