requests、selenium、xpath、bs4的使用以及爬取实例

使用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 = '(.+)'  # 括号表示分组,括号里的内容就是我们需要的
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="">(.+?)'    # 取标题
    pattern2 = 'data-el="region">(.+?)\s+\s+(-)\s+ \
               'href=".+?" ' \
               'target="_blank">(.+?)'    # 取地址
    pattern3 = '
(\d+?|\d+\.\d+?)(万)
\ 'class="unitPrice" data-hid="\d+?" data-rid="\d+?" ' \ 'data-price="\d+?">(.+?)' # 取总价和价格 # 将找到的信息存入列表 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 = """
The Dormouse's story

The Dormouse's story

Once upon a time there were three little sisters; and their names were , Lacie and Tillie; and they lived at the bottom of a well.

...

"""
soup = bs4.BeautifulSoup(html, 'lxml') # lxml是一种格式,BeautifulSoup()相当于一个修饰方法,把字符串转换为lxml格式 # print(soup) # print(type(soup)) # # 格式化代码,把格式不规范的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 = 'https://blog.csdn.net/qq_51136340/article/details/119696458?spm=1001.2014.3001.5501'
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 = """
1
    永辉超市2
    
中国
3
四川成都
4
肖家河大厦
5 6 7 8
"""
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('写入完成')

你可能感兴趣的:(笔记)