关于爬虫那档事

目录

    • 前言
    • requests爬取
    • 数据解析
      • re正则化
      • bs4
      • xpath
    • selenium
      • 验证码

前言

本文主要以代码形式讲解爬虫,代码中有注释可助理解,代码都是可以运行的,或许有些网站变化,导致无法访问或者属性元素找不到,要想运行的话,自个在网站里找元素位置并在代码中更改。
代码都是在PyCharm编译下写的,读者也可以下个PyCharm,还是很好用的。

顺便说几个快捷键,都是对于选中的语句:
Tab			#换行
Shift+Tab			#取消换行
Ctrl+?键			#多行注释(取消注释)

爬虫分类
还是先说下分类吧(教科书式,)

•	通用爬虫:通用爬虫是搜索引擎(Baidu、Google、Yahoo等)“抓取系统”的重要组成部分。
主要目的是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份。
简单来讲就是尽可能的;把互联网上的所有的网页下载下来,放到本地服务器里形成备分,在对这些网页做相关处理(提取关键字、去掉广告),最后提供一个用户检索接口。
•	聚焦爬虫:聚焦爬虫是根据指定的需求抓取网络上指定的数据。
例如:获取豆瓣上电影的名称和影评,而不是获取整张页面中所有的数据值。
•	增量式爬虫:增量式是用来检测网站数据更新的情况,且可以将网站更新的数据进行爬取
•	深层网络爬虫:大部分不能通过静态的URL获取,隐藏在搜索表单之后,只有用户提交一些关键词之后才能获得的网络页面。

requests爬取

爬取步骤:
1、指定url
2、发送请求
3、获取响应
4、数据解析
5、永久化存储

下面算是最基本的爬虫了,其中没有数据解析,看下爬取过程就行了

# -*- coding: utf-8 -*-
#加上面这个是防止中文乱码
import requests
#爬取河南理工大学主页
# 1 指定URL
get_url = "http://www.hpu.edu.cn/www/index.html"
#UA伪装
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'
}
# 2 发送请求
response = requests.get(url = get_url, headers = header)
# 3 获取响应数据
response.encoding = 'utf-8'
page_text =  response.text
# 4 永久化存储
fp = open("hpu.html",'w',encoding = 'utf-8')
fp.write(page_text)
fp.close()

get参数
下面代码是get请求时带有params参数,算是获取动态数据,获取到的是json类型的响应数据

# -*- coding: utf-8 -*-
import requests
import json
#豆瓣电影
url="https://movie.douban.com/j/chart/top_list?"
headers ={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"}
start = input("请输入起始位置:")
limit = input("请输入电影数量:")
params = {
        'type': '24',
        'interval_id': '100:90',
        'action':'' ,
        'start': start,
        'limit': limit
}
response = requests.get(url=url,params=params,headers=headers)
movie = response.json()
fp = open("douban.json",'w',encoding='utf-8')
json.dump(movie,fp=fp,ensure_ascii=False)
fp.close()
response.close()

post请求参数

# -*- coding: utf-8 -*-
import requests
import json
#百度翻译
url="https://fanyi.baidu.com/sug"
headers ={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"}
word = input("请输入想要查询的单词:")
data = {
        "kw": word
}
response = requests.post(url=url,data=data,headers=headers)
dic = response.json()
print(dic["data"][0]['k'])
print(dic["data"][0]['v'])
filename = word+".json"
fp = open(filename,'w',encoding='utf-8')
json.dump(dic,fp=fp,ensure_ascii=False)
fp.close()

运行结果:
关于爬虫那档事_第1张图片
生成的json文件,类型是字典:
在这里插入图片描述

数据解析

re用到的语句

import re
re.compile(pattern, flags=0)		#将一个正则表达式模式编译为一个正则表达式对象
re.findall(pattern, string, flags=0)	#匹配到字符串中所有符合条件的元素
re.finditer(pattern, string ,flags=0)
.groups()		#匹配对象函数来获取匹配表达式。
.sprit()		#去掉字符串里空格和换行

bs4语句

from bs4 import BeautifulSoup			#调用库
page=BeautifulSoup(string,'lxml')		#先将字符串转换为bs4识别的类型
table = page.find("table",class_="hq_table")              #class属性:class_
table = page.find("table",attrs={"class":"hq_table"})		# #指定属性 
trs = table.find_all("tr")		#找到所有tr标签

#获取文本
.string
.text
.get_text()

.get('title')		#用.get(‘属性值’)的方法获取标签里面的属性值

xpath语句

from lxml import etree
tree = etree.HTML(html)		#解析
/div[@class='coll']		#指定属性
/text()		#获取文本
/@href		#获取属性
/

三个特点:
re正则表达式:具有灵活、逻辑性和功能性非常强的特点,能迅速地通过表达式从字符串中找到所需信息的优点,但对刚接触的人,比较晦涩难懂。
bs4:提供了一些简单的函数用来处理导航、搜索、修改分析树等功能,可为用户提供需要抓取的数据,非常简便,仅需少量的代码就可以写出一个完整的应用程序,不仅支持python标准库中的HTML解析器,还支持一些第三方的解析器。
xpath:选择功能十分强大,提供了非常简洁明了的路径选择表达式,提供了超过100个内建函数,用于字符串、数值、时间的匹配,以及节点、序列的处理等等,几乎所有定位的节点都可以用Xpath来选择。

re正则化

正则的语法:使用元字符进行排列组合用来匹配字符串
安装re库

.*			贪婪匹配,匹配所有符合的
.*? 		惰性匹配 ,只匹配第一次成功

关于爬虫那档事_第2张图片

正则化匹配

# -*- coding: utf-8 -*-
import re
content = """
河南理工
郑州大学
河南大学
河南科大
"""
obj = re.compile(r"
r"'>(?P.*?)
"
,re.S) #re.S必须要带,不然.*不匹配 result = re.findall(obj,content) print(result)

运行结果:
在这里插入图片描述

爬取豆瓣Top250前十页

# -*- coding: utf-8 -*-
import requests
import re

url = 'https://movie.douban.com/top250'
hd = {
    'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Mobile Safari/537.36'
}

f = open("movie.txt",'w',encoding='utf-8')
for i in range(10):
    n = i*25
    params = {
        'start': n,
        'filter': ''
    }
    #url = url + '?start={}&filter='.format(n)
    response = requests.get(url, headers=hd, params=params)
    response.encoding = 'utf-8'
    page_text = response.text
    #print(page_text)
    obj = re.compile(r'
  • .*?
    .*?' r'(?P.*?).*?

    .*?
    (?P.*?)' r' .*?

    .*?property="v:average">(?P.*?)' r'.*?(?P.*?)人评价',re.S) result = re.finditer(obj,page_text) for res in result: f.write(res.group("name")) f.write('\t') f.write(res.group("year").strip()) f.write('\t') f.write(res.group("score")) f.write('\t') f.write(res.group('num')) f.write('\n') print('第{}页完成'.format(i+1)) f.close()
  • 运行结果:
    生成movie.txt文件:
    关于爬虫那档事_第3张图片

    bs4

    bs4:通过标签的特征定位到想要获取的内容
    安装BeautifulSoup库

    (1)根据标签名查找
        - soup.a   只能找到第一个符合要求的标签
    (2)获取属性
        - soup.a.attrs  获取a所有的属性和属性值,返回一个字典
        - soup.a.attrs['href']   获取href属性
    (3)获取其标签内的内容
        - soup.a.string
        - soup.a.text
        - soup.a.get_text()
       【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
    (4)find:找到第一个符合要求的标签
        - soup.find('a')  找到第一个符合要求的
        - soup.find('a', title="xxx")
        - soup.find('a', alt="xxx")
        - soup.find('a', class_="xxx")		#属性值查找
        - soup.find('a', id="xxx")
    (5)find_all:找到所有符合要求的标签
        - soup.find_all('a')
        - soup.find_all(['a','b']) 找到所有的a和b标签
        - soup.find_all('a', limit=2)  限制前两个
    (6)根据选择器选择指定的内容
               select:soup.select('#feng')
        - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
    	【注意】select选择器返回永远是列表,需要通过下标提取指定的对象
    
    #获取文本
    .string
    .text
    .get_text()
    .string可以返回当前节点中的内容,但是当前节点包含子节点时,.string不知道要获取哪一个节点中的内容,故返回空
    .text(或.get_text())可以返回当前节点所包含的所有文本内容,包括当前节点的子孙节点
    

    string与text:
    关于爬虫那档事_第4张图片

    bs4新发地代码实例

    # -*- coding: utf-8 -*-
    import requests
    import csv
    from bs4 import BeautifulSoup
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"
    }
    
    url="http://www.xinfadi.com.cn/marketanalysis/0/list/1.shtml"
    resp = requests.get(url=url,headers=headers)
    #print(type(resp.text))
    page=BeautifulSoup(resp.text,'lxml')
    #print(type(page))
    # table = page.find("table",class_="hq_table")              #class属性:class_
    table = page.find("table",attrs={"class":"hq_table"})       #指定属性
    #print(type(table),table)
    trs = table.find_all("tr")      #匹配所有tr标签
    vegs = trs[1:]
    #print(vegs[0].string)
    fp = open("price.csv","w",newline='',encoding="utf-8")     #有中文,utf-8编码格式,newline是防止多出现一行
    csvwriter = csv.writer(fp)
    for tr in vegs:
        tds = tr.find_all("td")
        #print(tds)
        name = tds[0].string    #菜名
        lowest = tds[1].string  #最低价
        aver = tds[2].string    #平均价
        highest = tds[3].string     #最高价
        scale = tds[4].string       #规格
        unit = tds[5].string        #单位
        date = tds[6].string        #发布日期
        #print(name+","+lowest+','+aver)
        csvwriter.writerow([name,lowest,aver,highest,scale,unit,date])      #csv保存方式
    fp.close()
    print('ok')
    #爬取十页
    # for i in range(10):
    #     url = f'http://www.xinfadi.com.cn/marketanalysis/0/list/{i + 1}.shtml'
    #     r = requests.get(url,headers=hd).content.decode('utf-8')
    #     page = BeautifulSoup(r,'lxml')
    #     tbody = page.find('div',class_='hangqing').find('table',class_='hq_table').findAll('tr')[1:]
    #     for tr in tbody:
    #         print(tr.text)
    

    运行结果:
    生成price.csv文件:
    关于爬虫那档事_第5张图片

    xpath

    xpath用路径找到数据
    安装lxml库

    代码实例

    # -*- coding: utf-8 -*-
    from lxml import etree
    html = """
    
        
            
             河南理工大学 
        
        
            

    计算机学院

    """
    tree = etree.HTML(html) # print(tree) # result1 = tree.xpath("/html") # print(result1) # result2 = tree.xpath("/html/head/title/text()") # print(result2) #[' 河南理工大学 '] # result3 = tree.xpath("/html//li[1]/a/text()") # print(result3) #['搜狐'] result4 = tree.xpath("/html/body/div[@class='coll']/ul") #指定属性 # print(result4) #[] result5 = result4[0].xpath("./li") #./当前目录 # print(result5) for i in result5: # print(i) # print(i.xpath("./*/text()")) print(i.xpath("./a/@href")) #获取href属性

    运行结果:
    关于爬虫那档事_第6张图片

    selenium

    selenium是一个用电脑模拟人操作浏览器网页,可以实现自动化,测试等!还有就是只要是肉眼能在网页看到的selenium都能爬取,对动态数据爬取很是方便。

    准备工作:

    1. 安装seleniumm
      pip install selenium

    2. 下载浏览器驱动
      Firefox浏览器驱动:geckodriver
      Chrome浏览器驱动:chromedriver
      Edge浏览器驱动:MicrosoftWebDriver
      打开本地浏览器,查看浏览器版本,然后下载对应的驱动器版本
      下载后,(解压),把驱动器放到与python.exe同一目录下。用PyCharm的运行一个代码后有显示python.exe路径。

    selenium模拟浏览器爬取拉勾网职位信息

    # -*- coding: utf-8 -*-
    from selenium.webdriver import Chrome
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.keys import Keys
    from lxml import etree
    import time
    
    #隐藏浏览器,就浏览器不弹出来
    # opt = Options()
    # opt.add_argument('--headless')
    # opt.add_argument('--disable-gpu')
    # web = Chrome(options=opt)
    
    web = Chrome()
    url = 'https://www.lagou.com/'
    web.get(url)
    web.find_element_by_xpath('//*[@id="changeCityBox"]/ul/li[1]/a').click()    #选择城市
    time.sleep(1)
    web.find_element_by_xpath('//*[@id="search_input"]').send_keys('python',Keys.ENTER)    #搜索JAVA,回车
    for i in range(3):
        #爬取3页
        li_list = web.find_elements_by_xpath('//*[@id="s_position_list"]/ul/li')    #每页所有职业,列表
        for li in li_list:
            time.sleep(1)
            #//点进职业详细信息(就点击),这种方法以防页面有滚动,无法点击现象。
    
            element = li.find_element_by_xpath('./div[1]/div[1]/div[1]/a/h3')
            web.execute_script("arguments[0].click();", element)        #这种方法防止找不到元素
            #li.find_element_by_xpath('./div[1]/div[1]/div[1]/a/h3').click()
            
            #//切换新打开的窗口,即职业详细信息窗口
            handlers = web.window_handles
            web.switch_to.window(handlers[-1])
    
            time.sleep(1)   #停一秒是防止页面没有加载出来,元素找不到而出错
            job = web.find_element_by_class_name('position-head-wrap-position-name').text   #职业名
            company = web.find_element_by_class_name('company').text            #公司名
            salary = web.find_element_by_class_name('salary').text              #薪水
            adress = web.find_element_by_class_name('publish_time').find_element_by_class_name('company').text      #公司地址
            #下面try是找岗位职责,因为有些页面信息是折叠的,所以先判断下是否有可点击折叠元素
            try:
                web.find_element_by_xpath('//*[@id="container"]/div[1]/div[1]/div[1]/span').click()
                duty = web.find_element_by_xpath('//*[@id="job_detail"]/dd[2]/div').text
            except:
                duty = web.find_element_by_xpath('//*[@id="job_detail"]/dd[2]/div').text
            print(job,company,salary,adress[:-4],duty,'\n')
            web.close()    #关闭当前页面
            time.sleep(1)
            web.switch_to.window(handlers[0])       #转到最初那个窗口
        web.find_element_by_class_name('pager_next ').click()    #点击下一页
    #web.close()	#关闭浏览器
    #web.quit()		#关闭浏览器所有打开的窗口
    

    运行结果:
    关于爬虫那档事_第7张图片
    若是出错,下面出错信息,不是代码问题,因为你他这个网址会记录你访问次数啥的,很烦人,体验下这个过程就行了。
    在这里插入图片描述

    验证码

    有些登录操作需要验证码,本节讲selenium获取验证码过程
    首先你需要个识别验证码的第三方工具,这里推荐个超级鹰,关注公众能白嫖使用许多次,够支持你学会了。

    selenium验证码12306登录操作代码

    # -*- coding: utf-8 -*-
    import requests
    from selenium.webdriver import Chrome
    import time
    from PIL import Image
    from selenium.webdriver.common.action_chains import ActionChains
    from hashlib import md5
    
    url = 'https://kyfw.12306.cn/otn/resources/login.html'
    web = Chrome()
    web.get(url)
    web.maximize_window()       #窗口最大化
    # web.refresh()     #刷新
    web.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click()
    # time.sleep(1)
    web.find_element_by_xpath('//*[@id="J-userName"]').send_keys('帐号')      #这里需要输入你12306的帐号
    web.find_element_by_xpath('//*[@id="J-password"]').send_keys('密码')      #12306密码
    
    web.save_screenshot('page_.png')        #截全屏
    img = web.find_element_by_xpath('//*[@id="J-loginImg"]')        #找到验证码位置(通过属性定位)
    loc = img.location
    size = img.size                 #验证码大小
    rect = (loc['x'],loc['y'],loc['x']+size['width'],loc['y']+size['height'])           #验证码左上角和右下角坐标
    i = Image.open('./page_.png')
    code = './code_.png'
    frame = i.crop(rect)            #吧把验证码部分截下来
    frame.save(code)
    
    #下面类代码是超级鹰验证码识别框架,不用管
    class Chaojiying_Client(object):
    
        def __init__(self, username, password, soft_id):
            self.username = username
            password =  password.encode('utf8')
            self.password = md5(password).hexdigest()
            self.soft_id = soft_id
            self.base_params = {
                'user': self.username,
                'pass2': self.password,
                'softid': self.soft_id,
            }
            self.headers = {
                'Connection': 'Keep-Alive',
                'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
            }
    
        def PostPic(self, im, codetype):
            """
            im: 图片字节
            codetype: 题目类型 参考 http://www.chaojiying.com/price.html
            """
            params = {
                'codetype': codetype,
            }
            params.update(self.base_params)
            files = {'userfile': ('ccc.jpg', im)}
            r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
            return r.json()
    
        def ReportError(self, im_id):
            """
            im_id:报错题目的图片ID
            """
            params = {
                'id': im_id,
            }
            params.update(self.base_params)
            r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
            return r.json()
    
    
    chaojiying = Chaojiying_Client('用户帐号', '密码', '918789')	#帐号,密码用自己的 #用户中心>>软件ID 生成一个替换 96001
    im = open('code_.png', 'rb').read()			            #本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
    clicks = chaojiying.PostPic(im, 9005)['pic_str']        #pic_str是字典里的一个键,值是验证码(点击坐标)
    print(clicks)
    loc_all = clicks.split('|')
    #模拟图片验证码点击操作
    for xy in loc_all:
        x,y = xy.split(',')
        ActionChains(web).move_to_element_with_offset(img,int(x),int(y)).click().perform()
    
    web.find_element_by_xpath('//*[@id="J-login"]').click()     #点击登录
    
    #拖动滑块
    time.sleep(1)
    #web.switch_to.alert.accept()        #切换到弹出框
    huakuai = web.find_element_by_xpath('//*[@id="nc_1_n1z"]')
    #time.sleep(1)
    # move_to_gap(huakuai,get_track(300))
    
    # 防止12306禁止selenium
    #使用selenium滑动会被12306检测到,需要伪装一下
    script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
    web.execute_script(script)
    
    #滑块移动
    span = web.find_element_by_xpath('//*[@id="nc_1_n1z"]')
    action = ActionChains(web)
    action.click_and_hold(span)
    action.move_by_offset(350, 0).perform()
    action.release()
    
    print('登陆了成功!')
    

    代码运行说明:
    1、下面这个调一下,在设置里面。不调的话验证码截剪的不对
    关于爬虫那档事_第8张图片

    2、代码里需要填写两处帐号、密码,一个是12306、另一个是超级鹰的
    3、出错可能验证码没有成功,这个代码只会测试一次,没成功就重新运行代码。

    运行:
    截的网页:

    截剪的验证码:
    关于爬虫那档事_第9张图片
    输出:
    在这里插入图片描述

    好了,到此本片文章结束,希望你能有所收获,捏!

    你可能感兴趣的:(python,css,html)