使用requests三方库
requests三方库是初学者最常用的一个库。
常用的几种方法
1、get:传递请求;在get(url,headers)是最基本的传入参数。
2、text:读取服务器的响应内容。
3、encoding:查看当前网页的编码方式。
4、content:二进制响应内容。当我们读取图片等非文本内容的常用读取方式。
5、json:返回网页的jison格式的数据。
staus_code:响应状态码。
更详细的requests库的使用可查看该链接:requests三方库使用
代码实例
利用requests库以及正则表达式爬取豆瓣250上的电影名,链接。以第一部电影肖申克的救赎为例
"""
import requests # 导入requests
import re # 导入正则表达式
url = "https://movie.douban.com/top250"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/92.0.4515.131 Safari/537.36'
}
resp = requests.get(url=url, headers=headers) # 请求网页
print(resp.text) # 获取网页的相应内容
with open('豆瓣电影.html', 'wb') as file:
file.write(resp.content) # 将二进制响应写入一个html文件中,避免后期访问网页过度被封ip
with open('豆瓣电影.html','r',encoding='utf-8')as file:
content = file.read() # 读取写入的网页响应内容
re_str = '<img width="100" alt="(.+)" src="(.+)" class="">' # 括号表示分组,括号里的内容就是我们需要的
result = re.search(re_str,content)
print(result.span()) # 输出找到的字符串的起始与终止的下标位置,元组形式
print(result.group(1)) # 将分组的内容输出,0表示全部输出,否则按位置输出,1就是第一个分组
print(result.group(2))
print(result.groups()) # 将所有分组内容以元组形式输出
results = re.findall(re_str,content) # 将匹配的所有内容以列表输出
for result in results:
print(result)
# 查找下一个
result1 = re.search(re_str,content[10002:])
print(result1.groups())
爬取多页链家二手房信息
代码中的方法基本可囊括初学者爬取网页的大多数方法,大部分方法和上面的代码大致相同,只是加入循环进行多页爬取。在进行多页爬取是可以发现换页是网址是发生有规则变换,可根据网址的变化进行访问多页数据。
"""
import re
import requests
pages = 2
for page in range(1,pages+1):
url = f'https://cd.lianjia.com/ershoufang/pg{page}/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/92.0.4515.131 Safari/537.36'
} # headers可以在网页的检查源代码中找到
resp = requests.get(url=url, headers=headers)
# with open(f'{page}.html','w',encoding='utf-8')as file:
# file.write(resp.text)
content = resp.text
pattern1 = 'data-is_focus="" data-sl="">(.+?)</a>' # 取标题
pattern2 = 'data-el="region">(.+?)\s+</a>\s+(-)\s+<a ' \
'href=".+?" ' \
'target="_blank">(.+?)</a>' # 取地址
pattern3 = '<div class="totalPrice"><span>(\d+?|\d+\.\d+?)</span>(万)</div><div ' \
'class="unitPrice" data-hid="\d+?" data-rid="\d+?" ' \
'data-price="\d+?"><span>(.+?)</span>' # 取总价和价格
# 将找到的信息存入列表
result1 = re.findall(pattern1, content)
result2 = re.findall(pattern2, content)
result3 = re.findall(pattern3, content)
address = []
prices = []
# 爬取到的信息不是完整的需要后期调整
for i in result2:
a = ''.join(i)
address.append(a)
for i in result3:
a = ''.join(i)
prices.append(a)
print(len(result1), len(address), len(prices))
information = []
for i in range(len(result1)):
information.append(result1[i] + ', ' + address[i] + ', ' + prices[i])
print(information)
bs4讲解
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间。
详情点击:bs4详细讲解
直接代码讲解
这里需要一些HTML知识,读者自行学习,或者了解父子类等一些调用的知识就够了。
import bs4 # 导入bs4库,需要下载
# bs4:全称:beautiful soup 4。可以从HTML或者从XML中提取数据
html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
soup = bs4.BeautifulSoup(html, 'lxml') # lxml是一种格式,BeautifulSoup()相当于一个修饰方法,把字符串转换为lxml格式
# print(soup)
# print(type(soup)) # <class 'bs4.BeautifulSoup'>
# 格式化代码,把格式不规范的HTML转换成规范的
print(soup.prettify())
# 输出head包含内容
print(soup.head)
# 打印标签:只打印第一个标签内容
print(soup.head.title)
print()
# 打印标签内容4种方法
print(soup.head.title.string) # The Dormouse's story
print(soup.head.title.get_text()) # The Dormouse's story
print(soup.head.title.text) # The Dormouse's story
print(soup.head.title.contents) # ["The Dormouse's story"]
# 选择标签内容方法
# select:使用id,class,标签,属性,父子,后代,兄弟,相邻兄弟等选择器取选择标签,返回结果:列表
# select_one:使用id,class,标签,属性,父子,后代,兄弟,相邻兄弟等选择器取选择标签,返回结果:select结果中的第一个元素
p_list = soup.select('body > p')
print(p_list)
p_list1 = soup.select('body>.title')
print(p_list1)
p = soup.select_one('body>p')
print(p)
爬取中国新闻网当天的热点新闻
import datetime # 导入时间库
import re
import bs4
from 爬虫请求网页模板 import response # 自己封装的一个请求网页的函数
i = datetime.datetime.now() # 获取现在当前时刻的时间
now_time = str(i.month)+'-'+str(i.day) # 将当天的月和天以字符串形式拼接,形如:8-19
pages = 10 # 页数,当天新闻不止一页
for page in range(1,pages+1):
url = f'https://www.chinanews.com/scroll-news/news{page}.html' # 换页时网址的变换规律
resp = response(url) # 请求网页
resp.encoding = 'utf-8' # 更改编码方式
content = resp.text # 返回网页响应的内容
# print(content)
soup = bs4.BeautifulSoup(content, 'lxml') # 修饰
# print(type(soup))
news_lists = soup.select('#content_right > div.content_list > ul > li') # select方法将li标签所有的内容拿出来
for news_list in news_lists: # type: bs4.element.Tag
kind = news_list.select_one('li>.dd_lm>a') # 将li标签下新闻类型取出
content = news_list.select_one('li>.dd_bt>a') # 取标题
news_time = news_list.select_one('li>.dd_time') # 取时间
if news_time:
news_time = str(news_time.text)
news_time1 = re.findall('(\d{1,2}-\d{1,2})',news_time) # 利用正则表达式将时间中的月数天数取出
if news_time1[0] == now_time: #判断当前月数天数和新闻的是否一致,一致则输出当天的新闻
print(kind.text,content.text,news_time,sep=' ')
# 大致输出前几行
体育 “钢铁教练”金甲洙:心怀一方热爱 以中国为家 8-22 16:41
视频 猎人变身大山守护者:学会与野生动物和谐相处 8-22 16:39
国际 法国马赛接连发生两起枪击事件至少造成3人死亡 8-22 16:39
视频 海南大熊猫兄弟8岁生日会:吃五彩冰蛋糕 泡花瓣浴 8-22 16:38
selenium库的使用
Selenium是一个用于测试网站的自动化测试工具,支持各种浏览器包括Chrome、Firefox、Safari等主流界面浏览器,同时也支持phantomJS无界面浏览器。
详情可点击:selenium
在使用selenium库时,我们需要下载一个webdriver驱动文件,当然,下载的驱动得看我们使用的浏览器,一般推荐使用谷歌浏览器。Chromedrive驱动 使用方法:
第一种:将下载的exe驱动放在与当前的py文件同一个目录下,调用代码是:
wb = selenium.webdrive.Chrome(chromedriver.exe)
第二种:配置环境变量,将exe文件放在与谷歌浏览器chrome.exe所在的文件目录之下,然后将路径添加到 我的电脑–>属性–>系统设置–>高级–>环境变量–>系统变量–>Path中,这种方法不一定全都能成功,调用:
wb = selenium.webdrive.Chrome()
定为元素方式
定位一个元素 定位多个元素 含义
find_element_by_id find_elements_by_id 通过元素id定位
find_element_by_name find_elements_by_name 通过元素name定位
find_element_by_xpath find_elements_by_xpath 通过xpath表达式定位
find_element_by_link_text find_elements_by_link_tex 通过完整超链接定位
find_element_by_partial_link_text find_elements_by_partial_link_text 通过部分链接定位
find_element_by_tag_name find_elements_by_tag_name 通过标签定位
find_element_by_class_name find_elements_by_class_name 通过类名进行定位
find_elements_by_css_selector find_elements_by_css_selector 通过css选择器进行定位
定位一个元素 | 定位多个元素 | 含义 |
find_element_by_id | find_elements_by_id | 通过元素id定位 |
find_element_by_name | find_elements_by_name | 通过元素name定位 |
find_element_by_xpath | find_elements_by_xpath | 通过xpath表达式定位 |
find_element_by_link_text | find_elements_by_link_tex | 通过完整超链接定位 |
find_element_by_partial_link_text | find_elements_by_partial_link_text | 通过部分链接定位 |
find_element_by_class_name | find_elements_by_class_name | 通过标签定位 |
find_element_by_class_name | find_elements_by_class_name | 通过类名进行定位 |
find_element_by_css_selector | find_elements_by_css_selector | 通过css选择器进行定位 |
import time
from selenium import webdriver
# selenium 自动化测试
url = ''
url2 = 'https://www.baidu.com/'
url3 = 'https://www.taobao.com'
# 创建浏览器对象
b = webdriver.Chrome()
# 设置浏览器窗口大小,分辨率
# b.set_window_size(1920,1080)
# 设置全屏
b.maximize_window()
# 请求链接
b.get(url)
b.get(url2)
b.get(url3)
# 后退 返回到上一个点击的链接
b.back()
time.sleep(1)
# 前进
b.forward()
time.sleep(1)
# 打印网页源码
print(b.page_source) # str--->bs4
# 设置滚动条 原点在左上角
max_y = 10000
y = 0
while y<=max_y:
b.execute_script(f'window.scrollTo(0,{y})')
y += 500
time.sleep(1)
# 通过元素定位爬取需要的
contents = b.find_element_by_id('content_right')
print(contents.text)
news_title = b.find_element_by_class_name('dd_bt')
print(news_title.text)
news_href = b.find_element_by_css_selector('#content_right > '
'div.content_list > ul > li:nth-child(1) > div.dd_bt>a').get_attribute('href')
print(news_href)
time.sleep(1)
# 关闭浏览器,close关闭当前所在标签页,quit关闭所有标签页
# 浏览器打开时会产生垃圾缓存,close只关闭,不执行清理缓存操作,quit关闭的同时会清理缓存
b.close()
b.quit()
通过selenium自动登录淘宝
import time
import selenium.webdriver as wb
url1 = 'https://www.taobao.com/'
url2 = 'https://www.baidu.com/'
url3 = 'https://yys.163.com/'
# 创建设置对象
options = wb.ChromeOptions()
# 不加载图片
# options.add_argument('blink-settings=imagesEnabled=false')
# 创建对象
b = wb.Chrome(options=options)
b.get(url1)
# 打开新的标签页
b.execute_script('window.open()')
# print(b.window_handles)
# 切换标签页
b.switch_to.window(b.window_handles[1])
b.get(url2)
# 打开新标签
# b.execute_script('window.open()')
# 切换选项卡
# b.switch_to.window(b.window_handles[2])
# b.get(url3)
time.sleep(1)
# 切换选项卡
b.switch_to.window(window_name=b.window_handles[0])
# 登录,找到登录位置点击
b.find_element_by_class_name('h').click()
b.find_element_by_class_name('icon-qrcode').click()
# 隐式等待:全局等待
b.implicitly_wait(15)
# 检测信息是否被加载,就是是否扫描二维码
b.find_element_by_class_name('site-nav-login-info-nick ')
# 获取Cookie
Cookie = b.get_cookies()
print(Cookie)
# 将cookie写入文件
with open('Cookies.txt','w',encoding='utf-8')as file:
file.write(str(Cookie))
b.quit()
改进版
# 导入按键事件
from selenium.webdriver.common import keys
from Tools.i18n.pygettext import safe_eval
from selenium import webdriver
url = 'https://www.taobao.com/'
with open('Cookies.txt','r')as file:
cookie = file.read()
new_cookie = safe_eval(cookie)
b = webdriver.Chrome() # 加载
# 防止selenium被监测
# 先修改js,再加载js 不需要更改,只对淘宝有用
b.execute_cdp_cmd(
"Page.addScriptToEvaluateOnNewDocument",
{
"source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
}
)
# 先访问一次再访问一次
b.get(url)
for i in new_cookie:
# 传入的键所对应值不能是False
if i['secure']:
b.add_cookie(i)
# 再访问一次
b.get(url)
# b.quit()
# 定位搜索框
search = b.find_element_by_id('q').send_keys('三只松鼠大礼包')
# 定位搜索按钮
enter = b.find_element_by_class_name('tb-bg').send_keys(keys.Keys.ENTER)
# 滚动进度条
max_y = 5000
y = 0
while y<=max_y:
b.execute_script(f'window.scrollTo(0,{y})')
y += 1000
time.sleep(2)
print(b.page_source) # 打印源码
通过手动在终端输入账号密码登录
import getpass
import time
from selenium import webdriver
import requests
import lxml
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
# 创建设置对象
options = webdriver.ChromeOptions()
# 避免终端下执行代码报错
options.add_experimental_option("excludeSwitches", ['enable-automation', 'enable-logging'])
# 不加载图片, 提升速度
# options.add_argument('blink-settings=imagesEnabled=false')
url = 'https://www.taobao.com'
wb = webdriver.Chrome(options=options)
# 隐式等待
wb.implicitly_wait(10)
# 防止被检测
wb.execute_cdp_cmd(
"Page.addScriptToEvaluateOnNewDocument",
{
"source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
}
)
wb.get(url)
wb.find_element_by_class_name('h').click()
# wb.find_element_by_class_name('icon-qrcode').click()
user = input('请输入账号:')
password = getpass.getpass('请输入密码:')
# 输入账号
wb.find_element_by_id('fm-login-id').send_keys(user)
# 输入密码
wb.find_element_by_id('fm-login-password').send_keys(password)
# 登录
wb.find_element_by_class_name('fm-button').click()
# 显示等待
WebDriverWait(wb, 20).until(EC.text_to_be_present_in_element((By.CSS_SELECTOR,
'#J_SiteNavLogin > div.site-nav-menu-hd > div.site-nav-user > a'),
'再见来不及挥手740959626')) # 检测是否出现账户名
# 搜索商品
wb.find_element_by_id('q').send_keys('月饼')
wb.find_element_by_id('q').send_keys(Keys.ENTER)
# time.sleep(2)
wb.quit()
xpath解析
# xpath查找xml文档的语言
# xml用来存储和传输数据的,
import lxml
from lxml import etree
"""lxml专门处理xml和html数据的三方库
etree.XML():专门将xml格式的字符串转换成_Element对象,可以方便使用xpath方法
etree.HTML():专门将HTML格式的字符串转换成_Element对象,可以方便使用xpath方法
"""
xml_str = """
<supermarket>1
<name>永辉超市</name>2
<address>中国</address>3
<address name="one">四川成都</address>4
<address name="two">肖家河大厦</address>5
<goodsList>
<goods name="泡面" price="3.5" count="20"></goods>
<goods name="矿泉水" price="2" count="50"></goods>
<goods name="面包" price="5" count="15"></goods>
</goodsList>6
<worker_list>
<cashier name="张三" pay="4000"></cashier>
<shoppingGuide name="李四" pay="3500"></shoppingGuide>
</worker_list>7
<goods price="50" count="15">
<name>烟</name>
</goods>8
</supermarket>
"""
root = etree.XML(xml_str) # type: lxml.etree._Element
print(root)
"""
1、xpath语法:
/ -表示根节点
// -表示文档的任意节点
. -表示当前节点
.. -当前节点的父节点
@ -表示节点属性
2、实例
/supermarket-表示提取根节点supermarket的所有子节点
supermarket-表示提取supermarket子节点
//name-表示提取文档中的所有name节点
/supermarket/goodsList/goods/@name-提取supermarket根节点中的goodsList子节点的goods子节点的name属性
3、未知节点
* -提取当前位置所有后代节点
//* -提取当前位置下的所有后代节点
node()-提取当前位置的任何类型的子节点
4、谓语
/supermarket/address[1]-提取根节点下第一个address子节点
/supermarket/address[@name]-取根节点下有name属性的所有address节点
/supermarket/address[@name="one"] -提取根节点下name等于one的address子节点
/supermarket/address[last()-1]- 提取根节点下倒数第二个address子节点
5、取内容
/text()-取节点内容
/@name - 取节点中name属性
"""
# print(root.xpath('/supermarket/text()'))
# print(root.xpath('//name/text()'))
# print(root.xpath('/supermarket/goodsList/goods/@count'))
# print(root.xpath('/supermarket/name/text()'))
# print(root.xpath('*'))
# print(root.xpath('//*/text()'))
# print(root.xpath('node()'))
print(root.xpath('/supermarket/address[1]/text()'))
print(root.xpath('/supermarket/address[@name]/text()'))
print(root.xpath('/supermarket/address[@name="one"]/text()'))
print(root.xpath('/supermarket/address[last()-1]/text()'))
实战
链家二手房信息爬取并且存入csv文件
from lxml import etree
import requests
import lxml
import csv
from 爬虫请求网页模板 import response
url = 'https://cd.lianjia.com/ershoufang/'
resp = response(url)
# with open('链家二手房.html','w',encoding='utf-8')as file:
# file.write(resp.text)
with open('链家二手房.html', 'r', encoding='utf-8')as file:
content = file.read()
root = etree.HTML(content) # type: lxml.etree._Element
# print(root)
# 标题
title = root.xpath('/html/body/div[@class="content "]/'
'div[1]/ul/li/div[@class="info clear"]/div[@class="title"]/a/text()')
# 链接
href = root.xpath('//ul[@class="sellListContent"]/li/div[@class="info clear"]/div[@class="title"]/a/@href')
# 地址
address1 = root.xpath('//ul[@class="sellListContent"]/li/div[@class="info clear"]/'
'div[@class="flood"]/div[@class="positionInfo"]/a[1]/text()')
address2 = root.xpath('//ul[@class="sellListContent"]/li/div[@class="info clear"]/'
'div[@class="flood"]/div[@class="positionInfo"]/a[2]/text()')
address=[]
for info in zip(address1,['-'for i in range(30)],address2):
address.append(''.join(info).replace(' ',''))
# print(address)
# 总价
total_price = root.xpath('/html/body/div[@id="content"]/div[@class="leftContent"]/'
'ul[@class="sellListContent"]/li[@class="clear LOGVIEWDATA LOGCLICKDATA"]/'
'div[@class="info clear"]/div[@class="priceInfo"]/div[@class="totalPrice"]/span/text()')
# 单价
unit_price = root.xpath('/html/body/div[@id="content"]/div[@class="leftContent"]/'
'ul[@class="sellListContent"]/li[@class="clear LOGVIEWDATA LOGCLICKDATA"]/'
'div[@class="info clear"]/div[@class="priceInfo"]/div[@class="unitPrice"]/span/text()')
# 具体情况
infomation = root.xpath('/html/body/div[@id="content"]/div[@class="leftContent"]/'
'ul[@class="sellListContent"]/li[@class="clear LOGVIEWDATA LOGCLICKDATA"]/'
'div[@class="info clear"]/div[@class="address"]/div[@class="houseInfo"]/text()')
# print(infomation)
# 写入csv文件
with open('链家二手房.csv','w',encoding='utf-8',newline='')as file:
writer = csv.writer(file)
writer.writerow(['标题','链接','地址','详细信息','总价(万元)','单价'])
for row in range(len(title)):
writer.writerow([title[row],href[row],address[row],infomation[row],total_price[row],unit_price[row]])
print('写入完成')