python爬虫笔记

2021/6/4 20:23:43

本文主要是介绍python爬虫笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

前言
爬虫是什么:通过程序模拟人工操作浏览器,获取网页中的数据,说白了就是和html网页打交道,从网页中找到需要的数据
工具介绍:
初级爬虫主要用的python工具有,requests模块,aiohttp异步网络访问,selenium自动化网页工具

1、requests模块

request模块是python3中最基本也是最常用的网络请求模块,用于网页的get和post请求,常见的使用方法如下:
1、导入模块 import requests
2、设置头或者数据
3、访问get/post请求网页
4、网页解析
先简单介绍下怎么获取网络请求的的相关数据
打开网页,右键选择检查,切换到network网页找到相关的请求链接,找到请求地址和参数。如下图所示,是一个根据地址查询邮编的网站,通过查询发现请求的url格式是

Request URL: https://www.ip138.com/post/search.asp?area=%CB%D5%D6%DD&action=area2zip

网页请求的类型是get,带两个参数,分别是area和action,所以在用requests模块请求网页的时候,也需要采用将这个数据传递进去否则就不能得到正确的访问页面
在这里插入图片描述

import requests
headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'
    }
url= "https://www.ip138.com/post/search.asp"
#param中的数据可以根据分析网页的请求获得,谷歌浏览器是,右键选择检查,切换到network界面,来找到网页请求相关参数,param中的参数顺序要根据分析源网页得到的参数顺序一致,否则会访问失败
param = {
        # 'area': '%CB%D5%D6%',
        'area': name,
        'action':'area2zip', 
    }
 #将headers 和 参数传入请求链接,开始进行网络请求,并返回网络请求结果
response = requests.get(url=url, params=param,headers = headers)
#获取网页返回的文本,就是网页的html格式显示,获取网页数据后,可以用xpath或re来晒选出网页中需要的内容
text = response.text()  
#获取网页是视频或者图片,就用如下方式获取,然后再写入指定文件,
data = response.content()
#获取requests最终发送网络请求的地址,主要用于检查发送的网络请求地址是否有问题,参数顺序对不对等
real_url = response.request.url
#如果服务器返回的是json类型的数据用json模块转为字典,便于访问
import json
dic_obj = response.json()

最近一周使用了各个爬虫模块体验后,发现最后数据解析查找环节,各个模块有自己的方法,但都支持xpath查找,所以在网页数据解析环节,一定要学会用xpath语法。强烈推荐用xpath,遇到特别复杂就用正则表达式re模块,但正则表达式可读性非常低,新手不推荐

2、aiohttp协程异步请求模块

通常网页请求是
请求
|
等待数据
|
数据解析
|
请求下一个网页
|
等待数据
|
数据解析
这是一个串行执行过程,也最好理解,符合人做事的习惯,做完一件再做另外一件。但是这样效率并不高。在等待数据的阶段cpu是出于空闲状态,在数据解析阶段,这时网络io是处于空闲状态。如此下来,如果要请求的网页数量越多,那么效率影响就更多了。那如何提高效率呢,就需要用到异步请求处理

aiohtpp是python支持的比较好一个异步请求模块,与requests类似,只不过requests不支持异步处理。为了实现异步,需要python的协程配合

import aiohttp
import asyncio
#定义多个需要访问的链接列表
urls = [
	'www.baidu.com',
	'www.sohu.com',
	'www.hao123.com'
]
#定义函数
async def get_urls(url):
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(url=url,headers=headers) as response:
                #获取二进制数据
                # data = await response.read()
                text = await response.text()
    except Exception as e:
        print(e)
       
    print(url,len(text))

#协程处理
task_list=[]
loop = asyncio.get_event_loop()
import time
start = time.time()
for url in urls:
	c = get_urls(url)
	task = asyncio.ensure_futrue(c)
	task_list.append(task)
loop.run_until_complete(asyncio.wait(task_list))
print('耗时:',time.time()-start)
	

3、selenium模块

当使用了requsets模块后,爬取一些静态网页,图片数量较少的网页比较正常,如果爬取图片数量比较多的,会发现爬取的网页不全,因为图片或者视频网页都是分步加载的,加载时间较长。当网页还没有加载完成后,requests模块就返回的数据,导致最终解析不到有用的数据。
这时候就该selenium出场了
selenium是自动化浏览器软件,当软件运行时会打开一个浏览器网页,这个网页时可以在你的电脑桌面上显示的,并且可以模拟网页文本输入,按钮点击等效果。比较适合爬取大型网站,需要验证码登录的网站(前台手动输入用户名密码及验证码,爬虫还在后台运行)
安装
1、pip install selenium
2、安装浏览器驱动,建议安装谷歌驱动,且驱动的版本要与自己电脑上使用的浏览器版本一致。
-驱动下载安装可访问https://blog.csdn.net/kenny_pj/article/details/103646745
-驱动下载好后,windows下将解压后的.exe文件放入python的安装目录。比如:C:\Python38

selenium不支持异步,如果需要批量下载图片,最后下载环节还需要配合aiohttp模块进行

from selenium import webdriver
from selenium.webdriver.common.keys import keys
from selenium.webdriver import ChromeOpthions
from selenium.webdriver.chrome.options import Options

#默认是带前端界面,设置无界面浏览器,浏览器解密不会再前端显示
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')

#如果不设置,服务器是知道你是在用浏览器模拟软件访问网页,规避浏览器检测风险
option = ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
option.add_argument('-ignore-certificate-errors')
option.add_argument('-ignore -ssl-errors')

web = werdriver.Chrome(options=option,chrome_options=chrome_options)
#发送网络请求get/post
web.get(url=url)
#等待网络加载1s后再读取网页
web.implicitly_wait(1)
#获取网页文本,获取之后可以用lxml模块来实现xpath解析
text = web.page_source
#find系列函数
#find_element_by_id  获取属性值用get_attribute('href')
link =  web.find_element_by_id('1920x1080').get_attribute('href')
#获取标签里的内容,这是返回link标签下所有的文本内容,包含子标签
link_text = web.find_element_by_id('1920x1080').text

#find elements返回的是列表,find_element只返回第一个元素
pic_list = web.find_elements_by_xpath('//*[@id="showImg"]/li')
for pics in pic_list:
    a_url = pics.find_element_by_xpath('./a').get_attribute('href')


#获取搜索框标签
search_input = web.find_element_by_id('q')
#输入指定内容到搜索框
search_input.send_keys('手机')
#获取搜索按钮
# search_btn = web.find_element_by_class_name('btn-search tb-bg')
#程序出错,找不到btn

search_btn = web.find_element_by_class_name('btn-search')
#程序运行正常
search_btn = web.find_element_by_class_name('tb-bg')
#程序运行正常
#执行脚本,向下滑动一个屏幕
web.execute_script('window.scrollTo(0,document.body.scrollHeight)')

sleep(2)
# web.back()
#点击搜索按钮
search_btn.click()

web.get('http://www.baidu.com')
sleep(2)
#浏览器后退
web.back()
sleep(2)
#浏览器前进
web.forward()
sleep(2)

比较厉害的是动作链功能,可以实现网页内部元素的拖动功能:

--from selenium.wedriver import ActionChains
--创建动作链
   --action = ActionChains(web)
--执行动作,点击长按并拖动
   --action.click_and_hold(div)
   --action.move_by_offset(x,y).perform()
--释放动作链
   --action.release()

当页面有iframe时,iframe里面的标签直接用find是找不到的,要用web.switch_to.frame(‘iframe’)后再进行查找

4、xpath解析

如果模块自己不带xpath解析工具就要利用到lxml模块,
常用的几种用法如下
tree.xpath(./a/text()) 获取标签文本
tree.xpath(//a/text()) 获取从第一层开始搜到的第一个a标签的文本
tree.xpath(//a/@href) 获取从第一层开始搜到的第一个a标签的href属性文本
tree.xpath(//img[@id=“god”]/text()) 获取从第一层开始搜到的第一个id=god的img标签的文本

以解析本地的一个网页为例
网页

<?xml version="1.0" encoding="UTF-8"?>

<bookstore>

<book category="COOKING">
  <title lang="en">Everyday Italian</title>
  <author>Giada De Laurentiis</author>
  <year>2005</year>
  <price>50.00</price>
</book>

<book category="CHILDREN">
  <price>29.99</price>
  <title lang="en">Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
</book>

<book category="WEB">
  <p id = '1'>
  <title lang="en">XQuery Kick Start</title>
  <author>James McGovern</author>
  <author>Per Bothner</author>
  <author>Kurt Cagle</author>
  <author>James Linn</author>
  <author>Vaidyanathan Nagarajan</author>
  <year>2003</year>
  <price>49.99</price>
  </p>

  <p id = '2'>
  <title lang="en">Learning XML</title>
  <author>Erik T. Ray</author>
  <year>2003</year>
  <price>39.95</price>
  </p>

  <p id = '3'>
    <th>
        <a href="www.baidu.com">书本链接</a>
        <title lang="en">Learning python</title>
        <author>Erik Jack</author>
        <year>2009</year>
        <price>20.45</price>

    </th>
  </p>

</book>
</bookstore>

以下实验较为详细的验证需要用到的常用功能。
如果是requests的请求返回数据

from lxml import etree
import requests
text = requests.get(url).text()
tree = etree.HTML(tree)
label = tree.xpath('//*[@id="gaoren"]')

from lxml import etree

#读取所有book的名称

def  read_all_book_title(tree):
    title_content=[]
    #获取所有book标签
    # /必须从根节点开始   /booksstore/book  等价于 //book
    title_list = tree.xpath('//book')
    print('title_list',title_list)
    for title in title_list:
        #返回文本内容列表的地址
        title_name_t = title.xpath('./title/text()')
        print('titil_name_t',title_name_t,type(title_name_t))
        #判断列表是否为空,为空说明该book的下一级不是title。很明显book category="WEB"中,book下一级不是title
        if title_name_t :
            #选择第一个文本内容
            title_name = title_name_t[0]
            title_content.append(title_name)
        else:
            print('can not found book/title')
    print(title_content)

#结果输出
# title_list [<Element book at 0x22065d96e80>, <Element book at 0x22065d96d80>, <Element book at 0x22065d96ec0>]
# titil_name_t ['Everyday Italian'] <class 'list'>
# titil_name_t ['Harry Potter'] <class 'list'>
# titil_name_t [] <class 'list'>
# can not found book/title
# ['Everyday Italian', 'Harry Potter']

def  read_all_book_title1(tree):
    title_content=[]
    #获取所有book标签
    # /必须从根节点开始   /booksstore/book  等价于 //book
    title_list = tree.xpath('//book')
    print('title_list',title_list)
    for title in title_list:
        #返回文本内容列表的地址,找到book下面所有层级的title
        title_name_t = title.xpath('.//title/text()')
        print('titil_name_t',title_name_t,type(title_name_t))

        if title_name_t :
            #在<book category="WEB">中book/p下面有两个title,book/p/th下有一个title
            #会将这三个book放到同一个列表里
            length = len(title_name_t)
            for i in range(length):
                #选择第文本内容
                title_name = title_name_t[i]
                title_content.append(title_name)
        else:
            print('can not found book/title')
    print(title_content)

#结果输出
# title_list [<Element book at 0x2077ff8b180>, <Element book at 0x2077ff8b080>, <Element book at 0x2077ff8b1c0>]
# titil_name_t ['Everyday Italian'] <class 'list'>
# titil_name_t ['Harry Potter'] <class 'list'>
# titil_name_t ['XQuery Kick Start', 'Learning XML', 'Learning python'] <class 'list'>
# ['Everyday Italian', 'Harry Potter', 'XQuery Kick Start', 'Learning XML', 'Learning python']

#一次性获取所有book层级下面的文本信息
def  read_all_book_string(tree):
    title_content=[]
    #获取所有book标签
    # /必须从根节点开始   /booksstore/book  等价于 //book
    title_list = tree.xpath('//book')
    print('title_list',title_list)

    for lt in title_list:
        str = lt.xpath('string(.)')
        title_content.append(str)
    
    print(title_content)

#结果输出
# title_list [<Element book at 0x21a43ffb180>, <Element book at 0x21a43ffb200>, <Element book at 0x21a43ffb100>]
# ['\n  Everyday Italian\n  Giada De Laurentiis\n  2005\n  30.00\n', 
# '\n  Harry Potter\n  J K. Rowling\n  2005\n  29.99\n',
#  '\n  \n  XQuery Kick Start\n  James McGovern\n  Per Bothner\n  Kurt Cagle\n  James Linn\n  Vaidyanathan Nagarajan\n  2003\n  49.99\n  \n\n  \n  Learning XML\n  Erik T. Ray\n  2003\n  39.95\n  \n\n  \n    \n        Learning python\n        Erik Jack\n        2009\n        20.45\n\n    \n  \n\n']

#读取第一本book的title,可以采用列表的访问方式,但是要记住,这里的起始元素是1而不是0
def read_first_book_title(tree):
    title_content=[]
    title = tree.xpath('//book[1]/title/text()')[0]
    title_content.append(title)
    print(title_content)

#输出结果
#['Everyday Italian']

def read_all_price(tree):
    title_content=[]
    price_list = tree.xpath('/bookstore/book//price')
    for price in price_list:
        print(price)
        pc = price.xpath('./text()')
        print('pc',pc)
        if pc:
            title_content.append(pc[0])
        else:
            print('price is empty')
    
    print(title_content)

#输出结果
# <Element price at 0x18924b0b440>
# pc ['30.00']
# <Element price at 0x18924b0b580>
# pc ['29.99']
# <Element price at 0x18924b0b5c0>
# pc ['49.99']
# <Element price at 0x18924b0b600>
# pc ['39.95']
# <Element price at 0x18924b0b640>
# pc ['20.45']
# ['30.00', '29.99', '49.99', '39.95', '20.45']
# 指定url,发起请求,获取响应数据,存储

def read_price(tree):
    title_content=[]
    price_list = tree.xpath('/bookstore/book[price>25.00]//price')
    print('price_list',price_list)
    for price in price_list:
        print(price)
        pc = price.xpath('./text()')
        print('pc',pc)
        if pc:
            title_content.append(pc[0])
        else:
            print('price is empty')
    
    print(title_content)


#通过@来筛选不同属性
def read_webbook_price(tree):
    title_content=[]
    #通过@来筛选不同属性
    price_list = tree.xpath('/bookstore/book[@category="WEB"]//price')
    print('price_list',price_list)
    for price in price_list:
        print(price)
        pc = price.xpath('./text()')
        print('pc',pc)
        if pc:
            title_content.append(pc[0])
        else:
            print('price is empty')
    
    print(title_content)

#结果输出
# price_list [<Element price at 0x1df4994c680>, <Element price at 0x1df4994c580>, <Element price at 0x1df4994c6c0>]
# <Element price at 0x1df4994c680>
# pc ['49.99']
# <Element price at 0x1df4994c580>
# pc ['39.95']
# <Element price at 0x1df4994c6c0>
# pc ['20.45']
# ['49.99', '39.95', '20.45']

#@attri 与text()类似
def read_label_attri(tree):
    title_content=[]
    #@后用双引号
    link_t = tree.xpath('//book//p[@id="3"]//a')
    print(link_t)
    link = link_t[0].xpath('./@href')[0]
    title_content.append(link)
    link_name = link_t[0].xpath('./text()')[0]
    title_content.append(link_name)
    print(title_content)

#结果输出
# [<Element a at 0x2ecdc67b800>]
# ['www.baidu.com', '书本链接']

def read_all_title_and_price(tree):
    title_content=[]

#一下两行,交换title和price位置不会改变其二者在t_p_list中的位置。
#位置由html网页中标签的先后位置决定,网页中title 在前,price在后
#如果改变html中某组标签的位置,则在该位置上的t_p_list位置也会改变
    t_p_list = tree.xpath('//price | //title')
    # t_p_list = tree.xpath('//title | //price')
    print(t_p_list,len(t_p_list))
    for t_p in t_p_list:
        a_t_p = t_p.xpath('./text()')[0]
        print('a_t_p',a_t_p)
        title_content.append(a_t_p)

    print(title_content)

#结果输出
# [<Element title at 0x17d10adb840>, <Element price at 0x17d10adb980>, <Element title at 0x17d10adb9c0>, <Element price at 0x17d10adba00>, <Element title at 0x17d10adba40>, <Element price at 0x17d10adbac0>, <Element title at 0x17d10adbb00>, <Element price at 0x17d10adbb40>, <Element title at 0x17d10adbb80>, <Element price at 0x17d10adba80>] 10
# a_t_p Everyday Italian
# a_t_p 50.00
# a_t_p Harry Potter
# a_t_p 29.99
# a_t_p XQuery Kick Start
# a_t_p 49.99
# a_t_p Learning XML
# a_t_p 39.95
# a_t_p Learning python
# a_t_p 20.45
# ['Everyday Italian', '50.00', 'Harry Potter', '29.99', 'XQuery Kick Start', '49.99', 'Learning XML', '39.95', 'Learning python', '20.45']
#更改了第二组title和price的位置,则在列表中的位置也变了
# ['Everyday Italian', '50.00', '29.99', 'Harry Potter', 'XQuery Kick Start', '49.99', 'Learning XML', '39.95', 'Learning python', '20.45']

#获取第n个元素最好的方式是放到一个列表,通过列表的方式来访问,慎用last(),postion()等函数
def read_special_price(tree):
    price_content = []
#采用索引last position 访问的前提当前同名标签位于同一父标签下的同一层级,
#3个p标签都是位于book category="WEB"下,p[1]长度为1
    first_price = tree.xpath('//p')
    print(first_price)
    first_price = tree.xpath('//p[1]/@id')[0]
    print(first_price,len(first_price))
    first_price = tree.xpath('//p[last()]/@id')[0]
    print(first_price)
    first_price = tree.xpath('//p[last()-1]/@id')[0]
    print(first_price)
    first_price = tree.xpath('//p[position()<3]/@id')[0]
    print(first_price)
#运行结果
# [<Element p at 0x2ace423ca40>, <Element p at 0x2ace423c940>, <Element p at 0x2ace423ca80>]
# ['1']
# ['3']
# ['2']
# ['1', '2']
    

#price在不同的父标签下,所以所有的price都是放到了price[1]里面
#运行结果看到price[1]列表的长度为5

    first_price = tree.xpath('//price[1]/text()')
    print('all price:',first_price)

    first_price = tree.xpath('//price[1]/text()')[0]
    print('first price:',first_price,len(first_price))

    first_price = tree.xpath('//price[1]/text()')[1]
    print('first second price:',first_price)

    first_price = tree.xpath('//price[2]/text()')[0]
    print('second price:',first_price)

    last_price = tree.xpath('//price[last()]/text()')[0]
    print('last price:',last_price)

    last_second_price = tree.xpath('//price[last()-1]/text()')[0]
    print('last second price:',last_second_price)

    first_two_price = tree.xpath('//price[position()<3]/text()')[0]
    print('first two price:',first_two_price)

#运行结果
# all price: ['50.00', '29.99', '49.99', '39.95', '20.45']
# first price: 50.00 5
# first second price: 29.99
# Traceback (most recent call last):
#   File "e:/python/xpath/xpath_01.py", line 284, in <module>
#     read_special_price(tree)
#   File "e:/python/xpath/xpath_01.py", line 250, in read_special_price
#     first_price = tree.xpath('//price[2]/text()')[0]
# IndexError: list index out of range

if  __name__ == "__main__":
    tree = etree.parse('book.html')

    # read_all_book_title(tree)
    # read_all_book_title1(tree)
    # read_all_book_string(tree)
    # read_first_book_title(tree)
    # read_all_price(tree)
    # read_price(tree)
    # read_webbook_price(tree)
    # read_label_attri(tree)
    read_all_title_and_price(tree)
    # read_special_price(tree)



这篇关于python爬虫笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程