Python67-爬虫

爬虫的基础知识

爬虫的定义

只要是浏览器可以做的事情,原则上,爬虫都可以帮助我们做,即:浏览器不能够做到的,爬虫也不能做

网络爬虫:又叫网络蜘蛛(spider),网络机器人,就是模拟客户端发送网络请求,接受请求响应,一种按照一定的规则,自动地抓取互联网信息的程序

爬虫的分类

  • 通用爬虫

    通常指搜索引擎的爬虫(面对整个互联网)

  • 聚焦爬虫:

    针对特定网站的爬虫

  • 流程:


    Python67-爬虫_第1张图片
    爬虫的工作流程

ROBOTS协议

网站通过robots协议告诉搜索引擎那些页面可以抓取,那些页面不能抓取

例如:https://www.taobao.com/robots.txt(通常是网站后面加/robots.txt即可以看到,就是一个文本文件)

部分内容如下:

User-agent:  Baiduspider    #用户代理,可以理解为浏览器的身份标识,通过这个字段可以告诉服务器是什么样的程序在请求网站,Baiduspider即百度的搜索引擎
Allow:  /article    #表示允许爬的内容
Allow:  /oshtml
Allow:  /ershou
Allow: /$
Disallow:  /product/    #表示不允许该用户代理爬的内容
Disallow:  /

但是robots只是道德层面的约束

http和https

为了拿到和浏览器一模一样的数据,就必须要知道http和https


Python67-爬虫_第2张图片
在这里插入图片描述
  • http:

    超文本传输协议,明文方式传输,默认端口80

  • https:

    http+ssl(安全套接字层),会对数据进行加密,默认端口443

https更安全,但是性能更低(耗时更长)

浏览器发送http请求的过程

Python67-爬虫_第3张图片
在这里插入图片描述

ps:爬虫在爬取数据的时候,不会主动的请求css、图片、js等资源,就算自己爬取了js的内容,也只是字符串,而不会执行,故, 浏览器渲染出来的内容和爬虫请求的页面并不一样

爬虫要根据当前url地址对应的响应为准,当前url地址的elements的内容和url的响应不一样,特别要注意tbody,经常在elements中有而响应中无

  • 页面上的数据在哪里?

    • 当前url地址对应的相应中
    • 其他url地址对应的相应中,如ajax请求
    • js生成:1、部分数据在响应中,2、全部由js生成

url的格式

host:服务器的ip地址或者是域名
port:服务器的端口
path:访问资源的路径
query-string:参数,发送给http服务器的数据
anchor:锚点(跳转到网页的制定锚点位置,anchor也有主播的意思)

例:http://item.jd.com/11936238.html#product-detail,就是一个带锚点的url,会自动跳转到商品详情,但是要注意,一个页面带锚点和不带锚点的响应是一样的(写爬虫的时候,就可以直接删掉锚点的部分)

http请求格式

Python67-爬虫_第4张图片
在这里插入图片描述

如,在访问百度时,查看request headers的source时,就可以看到如下内容

GET http://www.baidu.com/ HTTP/1.1  
#请求方法:get;url:http:xxxx.com/;协议版本:http1.1,然后换行
Host: www.baidu.com
#请求头部:host;值:www.baidu.com;换行,以下类似
Proxy-Connection: keep-alive    #keep-alive表示支持长链接。为什么要用长连接:不用频繁握手挥手,提高效率
Upgrade-Insecure-Requests: 1    #升级不安全的请求:把http请求转换为https的请求
DNT: 1  #Do not track
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)    Chrome/76.0.3809.100 Safari/537.36  #浏览器的标识。名字/版本号。如果有模拟手机版的请求,改user agent即可,不同的user agent访问相同的url,可能会得到不同的内容
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3  #浏览器告诉服务器自己可以接受什么样的数据
Referer: http://baidu.com/
Accept-Encoding: gzip, deflate  #告诉服务器自己可以接受什么样的压缩方式
Accept-Language: en-US,en;q=0.9 #告诉服务器自己可以接受什么样语言的数据,q:权重,更愿意接受哪种语言
Cookie: BAIDUID=B8BE58B25611B7BBA38ECFE9CE75841F:FG=1; BIDUPSID=B8BE58B25611B7BBA38ECFE9CE75841F; PSTM=1565080210; BD_UPN=12314753; delPer=0; BD_HOME=0;    H_PS_PSSID=26522_1453_21118_29523_29521_29098_29568_28830_29221_26350_22159; BD_CK_SAM=1; PSINO=7; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; COOKIE_SESSION=218_0_3_0_0_7_1_1_1_3_76_2_0_0_0_0_0_0_1565599571%7C3%230_0_1565599571%7C1; rsv_jmp_slow=1565599826516; H_PS_645EC=2c80At1Is237xdMOfC3ju2q0qlWJ%2FFlbD5N50IQeTrCHyIEsZN6yQYBgLHI; B64_BOT=1   #cookie:保存用户的个人信息。ps:cookie和session的区别:cookie保存在浏览器本地,不安全,存储量有上限,session保存在服务器,更安全,往往没有上限。cookie又分为request cookie和reponse cookie,在浏览器中可以查看

除了以上字段,可能还有referer字段,表示当前url是从哪个url过来的;x-request-with字段,表示是ajax异步请求

以上字段中,主要是user agent(模拟浏览器),cookie(反反爬虫)

常见的请求方式

  • get:除了post,基本都用get,更常用

  • post:常用于提交表单的时候(安全),传输大文件的时候(美观)

响应状态码(status code)

  • 200:成功
  • 302/307:临时转移至新的url
  • 404:not found
  • 500:服务器内部错误

字符串知识复习

  • str类型和bytes类型

    • bytes:二进制类型,互联网上数据都是以二进制的方式传输的
  • str:unicode的呈现形式

ps:ascii码是一个字节,unicode编码通常是2个字节,utf-8是unicode的实现方式之一,是一变长的编码方式,可以是1、2、3个字节

编码和解码的方式必须一致,否则会乱码

爬虫部分重要的是理解,而不是记忆


Request模块使用入门

Q:为什么要学习requests,而不是urllib?

  1. requests的底层实现是就urllib,urllib能做的事情,requests都可以做;
  2. requests在python2和python3中通用,方法完全一样;
  3. requests简单易用;
  4. request能够自动帮我们解压(gzip等)网页内容

中文文档api:http://docs.python-requests.org/zh_CN/latest/index.html

基础使用

"""基础入门"""
import requests

r = requests.get('http://www.baidu.com')    #r即为获得的响应。所请求的所有东西都在r中
# 必须要包含协议(http或https);还有dlelete,post等方法

print(r)

print(r.text)   #text是一个属性,其实可以通过他的意思判断,text是一个名字,所以是属性,如果是方法,常为动词
#会自动根据推测的编码方式解码为str

print(r.encoding)   #根据头部推测编码方式,如果猜错了,我们解码的时候就必须自己指定解码的方式

print(r.content)    #也是属性,是一个bytes类型的数据。
print(r.content.decode())   #将bytes类型转换为str类型。默认的解码方式为utf-8
print(r.status_code)    #获取状态码
assert r.status_code == 200   #断言状态码为200,如果断言失败,会报错:assertionerror
#可以用此方法判断请求是否成功

print(r.headers)    #响应头,我们主要关注其中的set-cookie(在本地设置cookie)字段
print(r.request)    #关于对应相应的请求部分,是一个对象
print(r.request.url)    #请求的url地址
print(r.url)    #响应地址,请求的url地址和响应的url地址可能会不一样(因为可能和重定向)
print(r.request.headers)    #请求头,如果不设置,默认的user-agent是python-requests/x.xx.x

with open('baidu_r.txt','w') as f:    #测试:查看默认的user-agent访问时返回的内容
    f.write(r.content.decode())

"""
requests中解编码的方法:
1. r.content.decode()   #content的类型为bytes,必须再次解码
2. r.content.decode('gbk')
3. r.text       #text是按照推测的编码方式进行解码后的数据,他的类型为str
"""

发送带header的请求

具体的header到浏览器中进行查看

"""
为什么请求需要带上header?
    模拟浏览器,欺骗服务器,获取和浏览器一致的内容

header的形式:字典,形式:{request headers冒号前面的值:request headers冒号后面的值},大部分情况,我们带上user-agent即可,少数情况需要cookie
用法:requests.get(url,headers=headers) 
"""

import requests

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0'}

response = requests.get('https://www.baidu.com',headers=headers)

print(response.content.decode())    #会发现响应中的数据比不带header多许多

发送带参数的请求

#在url中带参数的形式
#例如:在我们百度搜索某东西时,就会带上一大堆参数,但是大部分可能是没有用的,我们可以尝试删除,然后我们在爬虫中带的参数只需要为其中不能删除的部分即可
"""
参数的形式:字典
kw={'wd':'长城'}
用法:requests.get(url,params=kw)
"""
import requests

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0'}

params = {'wd':'这里是中文'}
#如果参数含中文,其就会被自动编码,编码的后的形式含百分号,我们可以使用url解码来查看原来的内容

r = requests.get('https://www.baidu.com',params=params,headers=headers)
print(r.status_code)
print(r.request.url)
print(r.url)
print(r.content.decode())

#当然,我们也可以直接把参数拼接到url中去,而不单独传参(也不需要手动编码),eg:r = requests.get('https://www.baidu.com/s?wd={}'.formate('传智播客'))

小练习:爬贴吧前1000页

import requests
kw = input('请输入您要爬取的贴吧名:')
url = 'https://tieba.baidu.com/f?kw=%{kw}8&pn='.format(kw=kw)
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0'}


for i in range(1000):
    url = urlr.formate(str(i*50))
    r = requests.get(url=url, headers=headers)
    with open('./tieba_pages/{}-第{}页.html'.format(kw,i), 'w', encoding='utf-8') as f:
        # 为什么是utf-8,因为r.content.decode()为utf-8的格式
        f.write(r.content.decode())

扁平胜于嵌套:比如,多用列表推倒式替代某些循环


Request深入

发送post请求

用法:

response = requests.post('https://www.baidu.com',data=data,headers=headers)
post时不仅需要地址,还需要我们post的数据,该数据就放在data中
data的形式:字典

使用代理

Python67-爬虫_第5张图片
在这里插入图片描述

正向代理与反向代理
Python67-爬虫_第6张图片
在这里插入图片描述

反向代理:浏览器不知道服务器的地址,比如以上的图例中,浏览器知道的只是nginx服务器,因此,及时有攻击,也只能攻击nginx,不能攻击到我们的服务器

正向代理:浏览器知道服务器的地址

爬虫为什么要使用代理

  • 让服务器以为不是同一个客户端在请求
  • 防止我们的真实地址被泄漏,防止被追究

使用代理

用法:requests.get('http://www.baidu.com',proxies=proxies)
proxies的形式是字典

proxies={
   'htttp':'http://12.34.56.78:8888', #如果请求的是http
   'https':'https://12.34.56.78:8888' #如果请求的是https的地址
}

免费代理的网址:https://proxy.mimvp.com/free.php

代理一般可以分为3种:

  • 透明代理
  • 普匿代理,透明以及普匿,对方是可以追查到我们的真实ip的
  • 高匿代理

要注意,不是所有的ip都支持发送https的请求,有些也不支持发送post请求

代码示例:

"""
0. 准备大量ip地址,组成ip池,随机选择一个ip地址来使用
    - 如何随机选择ip
        - {'ip':ip,'times':0}
        - [{},{},...{}],对这个ip的列表按照使用次数进行排序
        选择使用次数较少的几个ip,从中随机选择一个
1. 检查代理的可用性
    - 使用request添加超时参数,判断ip的质量
    - 在线代理ip质量检测的网站
"""
import requests

proxies = {"http":'http://123.56.74.13:8080'}

headers = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1'
}

r = requests.get('http://www.baidu.com', proxies=proxies,headers=headers)

print(r.status_code)
print(r.request.url)

session和cookie的使用与处理

cookie和session的区别

  • cookie存储在客户的浏览器上,session存储在服务器上
  • cookie的安全性不如session,别人可以分析存放在本地的cokie并进行cookie欺骗
  • session会在一定时间内保存在服务器上,当访问增多,会比较比较占用服务器的性能
  • cookie保存的数据容量有限(通常是4k),很多浏览器限制一个站点最多保存20个cookie

爬虫处理cookie和session

  • 带上 cookie和session的好处:

    能够请求到登录之后的页面

  • 带上cookie和session的弊端:

    一套cookie和session往往和一个用户对应,请求太快、次数太多,容易被服务器识别为爬虫

不需要cookie的时候尽量不去使用cookie

但是为了获取登录之后的页面,我们必须发送带有cookies的请求

携带cookie请求:

  • 携带一堆cookie进行请求,把cookie组成cookie池

如何使用

requests提供了一个叫做session的类,来实现客户端和服务器端的会话保持

  1. 实例化一个session对象:session = requests.session()
  2. 让session发送get或post请求:r = sessioon.get(url=url,data=post_data, headers=headers)

请求登录之后的网站的思路:

  • 实例化session
  • 先使用session发送请求,登陆对应网站,把cookie保存在session中,这里请求时,url应是表单的action的值,如果没有action项,就尝试抓包,看看当我们提交的时候,究竟给哪个网址发送了post请求;post_data是表单中的要提交的数据,其键为name
  • 再使用session请求登录之后才能访问的网站,session能够自动的携带登录成功时保存在其中的cookie,进行请求

案例:访问淘宝的登录后的页面

import requests

sesssion = requests.session()

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0'}
#注意:在copy User-Agent时,一定要复制全,不能直接在查看的时候copy,容易带上省略号
post_url = 'https://login.m.taobao.com/login.htm'
#post的url一般是在源码中表单的action中找

post_data = {
    'TPL_username':'xxxx',
    'TPL_password2':'xxxx'
}#表单中要填写的项

sesssion.post(url=post_url, data=post_data, headers=headers)

r = sesssion.get('https://h5.m.taobao.com/mlapp/mytaobao.html',headers=headers)

with open('taobao.html', 'w', encoding='utf-8') as f:
    f.write(r.content.decode()) #会发现taobao.html中的代码与我们登录淘宝后的https://h5.m.taobao.com/mlapp/mytaobao.html的代码一样,即成功访问了登录淘宝后的页面

不发送post请求,使用cookie获取登录后的页面

即:直接将cookie加在headers里面,而不必使用session进行post

如:

import requests

headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36',
    'Cookie':'xxxx'
}
url = 'https://i.taobao.com/my_taobao.htm'

r = requests.get(url=url, headers=headers)

print(r.content.decode())

也可以对cookies以参数形式传递,cookies为字典

r = requests.get('http://xxxx',headers=headers, cookies=cookies)
  • cookie过期时间很长的
  • 在cookie过期之前能够拿到所有的数据,比较麻烦
  • 配合其他程序一起使用,其他程序专门获取cookie,当前程序专门请求页面

寻找登录的post地址

  • 在form表单中查找actiond的url地址

    • post的数据是input标签中的name的值作为键,真正的用户名密码作为值的字典,post的url地址就是action对应的url地址
  • 抓包,看看当我们提交的时候,究竟给哪个网址发送了post请求

    • 勾选perserve log按钮,防止页面跳转找不到url

    • 寻找post数据,确定参数

      • 参数不会变:(如何确定参数会不会变?多请求几次),直接用,比如密码不是动态加密的时候

      • 参数会变

        • 参数在当前的响应中
        • 通过js生成:定位到对应的js查看

定位想要的js

  • 法一:对于Chrome浏览器

    • 选择登录按钮(或任意绑定了js事件的对象)
    • Eventlistener
    • 勾选Framework listeners
    • 查看对应的js
    • 找到登录按钮对应的函数
    • (如果遇到某个元素(如:$('.password').value)是干嘛的,可以copy到console中去进行查看;也可以直接对js添加断点)
  • 法二:对于Chrome浏览器

    • 直接通过Chrome中的search all file的搜索url中的关键字
  • 法三

    添加断点的方式来查看js的操作,通过python进行同样的操作,就可以得到js生成的数据

Requests的小技巧

cookie对象与字典的相互转化与url编解码

"""1. 把cookie对象(cookiejar)转化为字典"""
import requests
r = requests.get('http://www.baidu.com')
print(r.cookies)
ret = requests.utils.dict_from_cookiejar(r.cookies)
print(ret)  #输出:{'BDORZ': '27315'}
"""将字典转化为cookiejar"""
print(requests.utils.cookiejar_from_dict(ret))

"""2. url地址的编解码"""
url = 'http://www.baidu.com'
print(requests.utils.quote(url))    #输出:http%3A//www.baidu.com
print(requests.utils.unquote(requests.utils.quote(url)))    #输出:http://www.baidu.com

"""输出结果如下:
]>
{'BDORZ': '27315'}
]>
http%3A//www.baidu.com
http://www.baidu.com
"""

请求SSL证书验证与超时设置

如果某网站使用的是https,但是又没有购买ssl证书,等浏览器访问时就会提示不安全,而当我们使用爬虫爬取的就会报错,此时,我们可以用verify=False来解决

import requests
r = requests.get('https://www.12306.cn/mormhweb/',verify=False, timeout=10) #如果超时,会报错,因此要结合try使用
"""注意:此时不会报错,但是会warning"""

配合状态码判断是否请求成功

assert response.status_code == 200  #如果断言失败,会报错,因此应该结合try使用

重新请求

使用retrying模块,通过装饰器的方式使用

"""重新请求"""
import requests
from retrying import retry

headers= {
            'User-Agent':'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1'
        }
@retry(stop_max_attempt_number=3)   #即下面的方法最多可以报错3次,如果3次都报错,则程序报错
def _parse_url(url):
    r = requests.get(url,headers=headers,timeout=0.01)
    assert r.status_code == 200
    return r.content.decode()

def parse_url(url):
    try:
        html_str = _parse_url(url)
    except:
        html_str = None
    return html_str
if __name__ == "__main__":
    url = 'http://www.baidu.com'
    print(parse_url(url))

ps:安装第三方模块的方法

  • pip install
  • 下载源码文件,进入解压后的目录:python setup.py install
  • xxx.whl文件,安装方法:pip install xxx.whl

数据提取方法

基础知识

什么是数据提取

从响应中获取我们想要的数据

数据的分类

  • 非结构话数据:html等

    • 处理方法:正则表达式、xpath
  • 结构化数据:json、xml等

    • 处理方法:转化为python数据类型

主要是看结构清不清晰

数据提取之JSON

由于把json数据转化为python内奸数据类型很简单,所以爬虫缀,我们常使用能够返回json数据的url

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它使得人们很容易进行阅读和编写 。同时也方便了机器进行解析和生成,适用于进行数据交换的场景,比如网站前后台间的数据交换

Q:哪里能够找到返回json的url呢?

  • 使用chrome切换到手机页面
  • 抓包手机app的软件

Python67-爬虫_第7张图片
在这里插入图片描述

json.loads与json.dumps

"""
1. json.loads   能够把json字符串转换成python类型
2. json.dumps   能够把python类型转换为json字符串,当我们把数据保存问文本的时候常常需要这么做,如果要使其显示中文,可以使用参数:ensure_ascii=False;还使用使用参数:indent=2,使下一级相对上一级有两个空格的缩进
"""

使用json的注意点:

  • json中的引号都是双引号;

    • 如果不是双引号

      • eval:能实现简单的字符串和python类型的转化
      • replace:把单引号替换为双引号
  • 往一个文件中写如多个json串,不再是一个json串

    • 可以一行写一个json串,按照行来读取

json.load与json.dump

类文件对象:具有read和write方法的对象就是类文件对象,比如:f = open('a.txt','r'),f就是类文件对象(fp)

"""
1. json.load(类文件对象) #类型为dict
2. json.dump(python类型, 类文件对象)   #把python类型放入类文件对象中,也可以使用ensure_ascii和indent参数
"""

json在数据交换中起到了一个载体的作用,承载着相互传递的数据


Python67-爬虫_第8张图片
在这里插入图片描述

案例:爬取豆瓣

import requests
from pprint import pprint   #pprint:pretty print,实现美化输出
import json

from retrying import retry

url = 'https://m.douban.com/rexxar/api/v2/skynet/playlists?from_rexxar=true&for_mobile=1'

headers = {
    'User-Agent': 'Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Mobile Safari/537.36',
    # 'Sec-Fetch-Mode': 'cors'
    'Referer': 'https://m.douban.com/movie/beta'
    #在本次爬取过程中,必须加上Referer才行
}
@retry(stop_max_attempt_number=3)
def parse_url(url):
    r = requests.get(url,headers=headers, timeout=10)
    assert r.status_code == 200
    return r.content.decode()
    
resp_html = parse_url(url)
p_resp = json.loads(resp_html)
pprint(p_resp)
with open('douban.json','w', encoding='utf-8') as f:
    f.write(json.dumps(p_resp, indent=2, ensure_ascii=False))

douban.json中的部分内容如下:


Python67-爬虫_第9张图片
在这里插入图片描述

案例:爬取36kr

"""爬取36kr"""
import requests,json
from pprint import pprint
import re
url = 'https://36kr.com/'

headers = {
    'User-Agent':'Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Mobile Safari/537.36'
}
r = requests.get(url=url, headers=headers,timeout=3)
html_str = r.content.decode()
reg = '(.*?)'    #新闻的标题是直接在html中的
ret = re.findall(reg, html_str)
pprint(ret)

部分输出结果如下:


Python67-爬虫_第10张图片
在这里插入图片描述

爬虫思路总结

  • 通常,我们访问某个网站时,得到的是其主页的url
  • 得到了主页的url后,观察我们所需要的数据是否在主页对应的响应中,如果在,直接利用主页的url爬取
  • 如果不在主页的url中,查找我们需要的数据,得到其对应url,用该url进行数据的爬取
  • 如果相应数据不是在html中,而是json中,用json.loads对数据进行处理

正则表达式复习

所谓正则表达式,即:事先定义好一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤

常用的正则表达式的方法有

  • re.compile:编译
  • pattern.math:从头找一个
  • pattern.search:找一个
  • pattern.findall:找所以
  • pattern.sub:替换
Python67-爬虫_第11张图片
在这里插入图片描述

说明:

  • .的Dotall即模式即是在匹配时加上re.Dotall参数,或者re.S,使.能够匹配任意字符

  • 记忆:d:digit;s:space

  • sub的使用,re.sub(reg, new_str, old_str),将匹配到的内容替换为new_str

  • re.findall('a(.*)b', 'str'),能够返回括号中的内容,括号前后的内容起到定位和过滤的效果

  • r'a\nb' 可以匹配'a\nb';r'a\nb'而不能匹配'a\nb',r可以忽略转义符号带来的影响,待匹配的字符串里面有 几个\,正则表达式里面也写几个\即可

  • compile的作用

    • 将对应正则表达式能够匹配到的内容放到内存中去,加快匹配的速度
    • 使用方法:re.compile(reg)
  • compile和sub的结合使用

    b = hello1world2
    p = re.compile('\d')
    p.findall(b)
    p.sub('_',b)    #将b中的所有数字替换为下划线
    

    ps:如果是对.进行编译,若想使其能够匹配换行符等,则re.S需要加在编译的使用,而不是匹配的时候

贪婪模式与非贪婪模式

  • 非贪婪模式:.*?或者.+?
  • 贪婪模式:.*或者.+

XPATH和lXML

基础知识

lxml是一款高性能的python HTML/XML解析器,利用xpath,我们可以快速的定位特定元素以及获取节点信息

什么是xpath

xpath(XML Path Language)是一门在HTML/XML文档中查找信息的语言(既然是一种语言,就有自己的语法),克用来在html/xml中对元素和属性进行遍历

W3School官方文档:http://www.w3school.com.cn/xpath/index.asp

xml与html对比

Python67-爬虫_第12张图片
在这里插入图片描述

节点的概念:每个xml标签都称之为节点,比如下图中的</code>等</p> <div class="image-package"> <div class="image-container" style="max-width: 569px; max-height: 348px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/22c7b261e4234bb5b6af40db500f753d.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/22c7b261e4234bb5b6af40db500f753d.jpg" width="569" height="348" alt="Python67-爬虫_第13张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <br> <p>book节点是title等节点的父节点,title和author等是兄弟节点,此外,还有祖先节点等概念</p> <p><strong>常用节点选择工具</strong></p> <ul> <li>Chrome插件XPATH Helper</li> <li>开源的XPATH表达式编辑工具:XMLQuire(XML格式文件可用)</li> <li>FireFox插件 XPath Checker</li> </ul> <h2>XPATH语法</h2> <p>XPATH使用路径表达式来选取xml文档中的节点或者节点集。这些<strong>路径表达式</strong>和我们在常规的<strong>电脑文件系统</strong>中看到的表达式非常类似</p> <p><code>注意:我们写xpath的时候,看的是请求页的响应,而不是elements</code></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 271px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/01b7ee2450224bfe91b8d4f3abd5f8cc.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/01b7ee2450224bfe91b8d4f3abd5f8cc.jpg" width="650" height="238" alt="Python67-爬虫_第14张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <br> <p>使用Chrome插件的时候,当我们选中标签,该标签会添加属性class='xh-highlight'</p> <pre><code class="python">/html 即表示从根节点开始选中html标签 /html/head 选中html标签下的head标签 /html/head/link 选中html标签下的head标签中的所有link标签 </code></pre> <p><strong><code>xpath学习重点</code></strong></p> <ul> <li><p>使用xpath helper或者是Chrome浏览器中的copy xpath都是从element中提取的数据,但是爬虫获取的是url对应的响应,往往和elements不一样</p></li> <li> <p>获取属性</p> <ul> <li> <code>/html/head/link/@href</code> 选择html标签下的head标签下的(所有)link标签中的href属性的值</li> </ul> </li> <li> <p>获取文本</p> <ul> <li> <code>/html/head/link/text()</code> 即选取标签中的内容,innerHtml</li> <li> <code>/html//text()</code> 获取html下所有的标签文本</li> <li> <code>//a[text()='下一页']</code>选择文本为下一页三个字的a标签</li> </ul> </li> <li> <p>从当前节点往下开始选择与使用@进行元素的定位</p> <ul> <li> <code>//li</code> 选中文档中所有的li标签</li> <li> <code>//li//a</code> 文档中的所有li中的所有a标签</li> <li> <code>//ul[@id='detail-list']/li</code> 选中文档中的id为'detail-list'的ul标签下的li标签;如果没有id,也可以@class等</li> </ul> </li> </ul> <p><strong>选择特定节点</strong></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 433px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/9dbed70f7f924040a4471671245e7734.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/9dbed70f7f924040a4471671245e7734.jpg" width="650" height="350" alt="Python67-爬虫_第15张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <br> <p>上图中的部分说明:</p> <ul> <li> <code>/bookstore/book[price>35.00]</code>book用的是子节点中的price标签进行的修饰,此处price的形式为:<code><price>35.00</price></code> </li> </ul> <p><strong>选择未知节点</strong></p> <p></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 406px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/d5c42a02763a40fab2cb22b89162890c.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/d5c42a02763a40fab2cb22b89162890c.jpg" width="650" height="352" alt="Python67-爬虫_第16张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <br> <strong>选择若干路径(或的运用)</strong> <p></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 225px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/18cf4ee74e414de4a405c3b280a57984.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/18cf4ee74e414de4a405c3b280a57984.jpg" width="650" height="182" alt="Python67-爬虫_第17张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <h2>lXML库</h2> <p><strong>使用入门</strong></p> <pre><code class="python">""" 1. 导入lxml的etree库:from lxml import etree,注意,如果是在pycharm中,可能会报红,但是不影响使用 2. 利用etree.HTML,将字符串转化为Element对象 3. Element对象具有xpath的方法:html = etree.HTML(text) html.xpath('字符串格式的xpath语法') """ </code></pre> <p>应用举例:</p> <pre><code class="python">from lxml import etree from pprint import pprint text = """ <tr> <td class="opr-toplist1-right">586万<i class="opr-toplist1-st c-icon c-icon-up"></i></td> </tr> <tr> <td class="opr-toplist1-right">539万<i class="opr-toplist1-st c-icon c-icon-up"></i></td> </tr> <tr> <td class="opr-toplist1-right">444万<i class="opr-toplist1-st c-icon c-icon-up"></i></td> </tr> <tr> <td class="opr-toplist1-right">395万<i class="opr-toplist1-st c-icon "></i></td> """ html = etree.HTML(text) #html为一个Element对象 pprint(html) #查看element对象中包含的字符串(bytes类型) pprint(etree.tostring(html).decode()) #会发现把缺少的标签进行了补全,包括html和body标签 print(html.xpath('//td/text()')) #这里的html是上面etree.HTML(text)获得的对象,结果为列表 #只要是element对象,就可以使用xpath进行数据的提取 </code></pre> <p><strong>lxml注意点</strong></p> <ul> <li> <p>lxml可以自动修正html代码(但是不一定能正确修正,也可能改错了)</p> <ul> <li>使用etree.tostring查看修改后的样子,根据修改之后的html字符串写xpath</li> </ul> </li> <li> <p>提取页面数据的思路</p> <ul> <li>先分组,渠道:一个包含分组标签的列表</li> <li>遍历:取其中每一组进行数据的提取,不会造成数据对应错乱</li> </ul> </li> </ul> <p><strong>xpath的包含</strong></p> <ul> <li> <code>//div[contains(@class='li')]</code>获取包含有li样式类的标签的标签</li> </ul> <p><strong>爬虫的思路总结</strong></p> <ol> <li> <p>准备url</p> <ol> <li> <p>准备start_url</p> <ul> <li><p>url地址规律不明显,总数不确定</p></li> <li> <p>通过代码提取下一页url</p> <ul> <li>xpath:url在当前的响应里面</li> <li>寻找url地址,部分参数在当前的响应中,比如当前页面数和总的页码数(eg:通过js生成)</li> </ul> </li> </ul> </li> <li> <p>准备url_list</p> <ul> <li>页码总数明确</li> <li>url地址规律明显</li> </ul> </li> </ol> </li> <li> <p>发送请求,获取响应</p> <ul> <li><p>添加随机的User-Agent:反反爬虫</p></li> <li><p>添加随机的代理ip:反反爬虫</p></li> <li> <p>在对方判断出我们是爬虫之后,添加更多的header字段,包括cookie</p> <ul> <li><p>cookie的处理可以通过session来解决</p></li> <li> <p>准备一堆能用的cookie,组成cookie池</p> <ul> <li> <p>如果不登录,准备当开始能够请求对方网站的cookie,即接受对方网站设置在response的cookie</p> <ul> <li>下一次请求的时候,使用之前的列表中的cookie来请求</li> <li>即:专门用一个小程序来获取cookie,爬取数据再用另一个程序</li> </ul> </li> <li> <p>如果登录</p> <ul> <li>准备一堆账号</li> <li>使用程序获取每个账号的cookie</li> <li>之后请求登录之后才能访问的网站随机的选择cookie</li> </ul> </li> </ul> </li> </ul> </li> </ul> </li> <li> <p>提取数据</p> <ul> <li> <p>确定数据的位置</p> <ul> <li> <p>如果数据在当前的url地址中</p> <ul> <li> <p>提取的是列表页的数据</p> <ul> <li>直接请求列表页的url地址,不用进入详情页</li> </ul> </li> <li> <p>提取的是详情页的数据</p> <ul> <li>确定url地址</li> <li>发送请求</li> <li>提取数据</li> <li>返回</li> </ul> </li> </ul> </li> <li> <p>如果数据不在当前的url地址中</p> <ul> <li>在其他的响应中,寻找数据的位置</li> <li>使用chrome的过滤条件,选择除了js,css,img之外的按钮(但是可能出错)</li> <li>使用chrome的search all file,搜索数字和英文(有时候不支持搜索中文)</li> </ul> </li> </ul> </li> <li> <p>数据的提取</p> <ul> <li>xpath,从html中提取整块数据,先分组,之后没一组再提取</li> <li>json</li> <li>re,提取max_time,price,html中的json字符串</li> </ul> </li> </ul> </li> <li> <p>保存</p> <ul> <li>保存在本地,text、json、csv</li> <li>保存在数据库</li> </ul> </li> </ol> <h2>CSV</h2> <p>逗号分隔值,一种文件后缀,以纯文本的形式存储表格数据</p> <p>其文件中的一行对应表格的一行,以逗号分隔列</p> <hr> <h1>多线程爬虫</h1> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 231px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/82e6f89a01e942e29f3a0faffd424eb1.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/82e6f89a01e942e29f3a0faffd424eb1.jpg" width="650" height="200" alt="Python67-爬虫_第18张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <hr> <h1>动态HTML技术</h1> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 279px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/eea363f1902f435caf721c7141226d4d.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/eea363f1902f435caf721c7141226d4d.jpg" width="650" height="224" alt="Python67-爬虫_第19张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <h2>Selenium和PhantomJS</h2> <ul> <li> <p>Selenium</p> <p>Selenium是一个Web的自动化测试工具,可以控制一些浏览器(比如phantomJS),可以接受指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏</p> </li> <li> <p>PhantomJS</p> <p>phantomJS是一个基于Webkit的“无界面”浏览器,它会把网站加载到内存并执行页面上的javascript</p> </li> </ul> <p>下载地址:http://phantomjs.org/download.html</p> <h3>入门</h3> <pre><code class="python">"""1. 加载网页""" from selenium import webdriver driver = webdriver.PhantomJS("xxxx/phantom.exe") """除了PhantomJS,还有Chrome,FireFox等""" driver.get("http://www.baiud.com/") driver.save_screenshot("长城.pnh") """2. 定位和操作""" driver.find_element_byid("kw").send_keys("长城") drvier.finde_element_by_id("su").click() """3. 查看和请求信息""" driver.page_source() driver.get_cookies() driver.current_url() """4. 退出""" driver.close() #退出当前页面 driver.quit() #退出浏览器 """5. 其他""" #ps:无论是使用PhantomJS还是Chrome或是FireFox,driver的操作是一样的 </code></pre> <p><strong>基础使用示例</strong></p> <p>ps:chromedriver的下载地址(注意:版本一定要和你安装的Chrome浏览器的版本号一致):http://npm.taobao.org/mirrors/chromedriver/</p> <pre><code class="python">from selenium import webdriver """ selenium请求的速度很慢,因为是使用浏览器,会请求js、css等 """ phantom_path = r"D:\Green\phantomjs-2.1.1-windows\bin\phantomjs.exe" """在使用phatnomjs时,报了unexpected exit, status code 0的错误,尚未找到原因""" chrome_path = r"C:\Users\25371\Desktop\chromedriver_win32\chromedriver.exe" """注意:这里一定要是chromedriver.exe,而不是chrome.exe""" driver = webdriver.Chrome(executable_path=chrome_path) #实例化对象 # driver.maximize_window() #最大化窗口 driver.set_window_size(width=1920,height=1080) #设置窗口大小 driver.get("http://www.baidu.com") driver.find_element_by_id('kw').send_keys("python") #kw是百度的输入框的表单的id;send_keys就是往一个input标签里面输入内容 #以上的一行代码就可以时Chrome自己百度搜索python driver.find_element_by_id('su').click() #su是百度一下的按钮的id #click实现对按钮的点击 """获取当前的url""" print(driver.current_url) #注意:因为已经click了,所以是click后的地址 """截屏""" driver.save_screenshot("./baidu_python.png") """在本次截屏中,由于截屏太快而网页加载太慢,截屏的图中未能截到百度出来的结果""" """driver获取cookie""" cookies = driver.get_cookies() print(cookies) cookies = {i['name']:i['value'] for i in cookies} #使用字典推导式重新生成requests模块能用的cookies print(cookies) """获取html字符串""" """即elements""" print(driver.page_source) #page_source是一个属性,获得html字符串后,就可以直接交给xpath """退出当前页面""" driver.close() #如果只有一个窗口,close就是退出浏览器 """退出浏览器""" driver.quit() </code></pre> <p><strong>示例二</strong></p> <pre><code class="python">from selenium import webdriver from time import sleep chrome_path = r"C:\Users\25371\Desktop\chromedriver_win32\chromedriver.exe" driver = webdriver.Chrome(executable_path=chrome_path) driver.get('https://www.qiushibaike.com/text/page/1/') ret = driver.find_elements_by_xpath(".//div[@id='content-left']/div") for r in ret: print(r.find_element_by_xpath("./a[1]/div[@class='content']/span").text) """通过text属性获取文本""" print(r.find_element_by_xpath("./a[1]").get_attribute("href")) """通过get_attribute获取属性""" driver.quit() </code></pre> <p><strong>元素的定位方法</strong></p> <ul> <li>find_element_by_id 返回一个</li> <li>find_elements_by_id 返回一个列表</li> <li>find_elements_by_link_text</li> <li>find_elements_by_partial_link_text</li> <li>find_elements_by_tag_name</li> <li>find_element_by_class_name</li> <li>find_elements_by_class_name</li> <li>find_elements_by_css_selector</li> </ul> <p>注意:</p> <ul> <li>获取文本或属性时,需要先定位到对应元素,再使用text属性或者get_attribute方法</li> <li>element返回一个,elements返回列表</li> <li>link_text和partial_link_text的区别:全部文本和包含的某个文本,即partial可以只写部分文本,而link_text需要写完整</li> <li>by_css_selector的用法:#food span.dairy.aged</li> <li>by_xpath中获取属性和文本需要使用get_attribute()和.text</li> <li>selenium使用class定位标签的时候,只需要其中的一个class样式名即可,而xpath必须要写所有的class样式类名</li> </ul> <p>示例:</p> <pre><code class="python">from selenium import webdriver from time import sleep chrome_path = r"C:\Users\25371\Desktop\chromedriver_win32\chromedriver.exe" driver = webdriver.Chrome(executable_path=chrome_path) driver.get('https://www.qiushibaike.com/text/page/1/') ret = driver.find_elements_by_xpath(".//div[@id='content-left']/div") for r in ret: print(r.find_element_by_xpath("./a[1]/div[@class='content']/span").text) """通过text属性获取文本""" print(r.find_element_by_xpath("./a[1]").get_attribute("href")) """通过get_attribut获取属性""" print('-'*50) """find_element_by_link_text""" """根据标签里面的文字获取元素""" print(driver.find_element_by_link_text("下一页").get_attribute('href')) """partial_link_text""" print(driver.find_element_by_partial_link_text("下一").get_attribute('href')) """以上两行代码获得的东西相同""" driver.quit() </code></pre> <h3>深入</h3> <p><strong>iframe</strong></p> <p>iframe或frame里面的html代码和外面的html代码实质上是两个不同的页面,因此,有时候我们在定位元素时,明明elements里面有,但是会定位失败</p> <p>解决办法:使用driver.switch_to.frame或driver.switch_to_frame(已经被弃用)方法切换到对应frame中去</p> <p>driver.switch_to.frame的使用说明:</p> <pre><code class="python">def frame(self, frame_reference): """ Switches focus to the specified frame, by index, name, or webelement. :Args: - frame_reference: The name of the window to switch to, an integer representing the index, or a webelement that is an (i)frame to switch to. :Usage: driver.switch_to.frame('frame_name') driver.switch_to.frame(1) driver.switch_to.frame(driver.find_elements_by_tag_name("iframe")[0]) """ 源码 </code></pre> <p>代码示例:豆瓣登录</p> <pre><code class="python">from selenium import webdriver import time chrome_path = r"C:\Users\25371\Desktop\chromedriver_win32\chromedriver.exe" driver = webdriver.Chrome(executable_path=chrome_path) driver.get("https://douban.com/") login_frame = driver.find_element_by_xpath("//iframe[1]") driver.switch_to.frame(login_frame) driver.find_element_by_class_name("account-tab-account").click() driver.find_element_by_id("username").send_keys("784542623@qq.com") driver.find_element_by_id("password").send_keys("zhoudawei123") driver.find_element_by_class_name("btn-account").click() time.sleep(10) #暂停以手动进行验证 """获取cookies""" cookies = {i['name']:i['value'] for i in driver.get_cookies()} print(cookies) time.sleep(3) driver.quit() </code></pre> <p><strong>注意</strong></p> <ul> <li>selenium获取的页面数据 是浏览器中elements的内容</li> <li>selenium请求第一页的时候,会等待页面加载完了之后再获取数据,但是在点击翻页之后,会立马获取数据,此时可能由于页面还没有加载完而报错</li> </ul> <h3>其他</h3> <ul> <li> <p>cookies相关用法</p> <ul> <li>{cookie['name']:cookie['value'] for cookie in driverr.get_cookies()} 获取字典形式的cookie</li> <li>driver.delete_cookie('cookiename')</li> <li>driver.delete_all_cookies()</li> </ul> </li> <li> <p>页面等待</p> <p>页面等待的原因:如果网站采用了动态html技术,那么页面上的部分元素出现时间便不能确定,这个时候就需要一个等待时间</p> <ul> <li>强制等待:time.sleep(10)</li> <li>显示等待(了解)</li> <li>隐式等待(了解)</li> </ul> </li> </ul> <hr> <h1>Tesseract的使用</h1> <ol> <li><p>tesseract是一个<strong>将图像翻译成文字的OCR库</strong>,ocr:optical character recognition</p></li> <li> <p>在python中安装tesseract模块:pip install pytesseract,使用方法如下:</p> <pre><code class="python">import pytesseract from PIL import Image image = Image.open(jpg) #jpg为图片的地址 pytesseract.image_to_string(image) </code></pre> </li> </ol> <p>使用tesseract和PIL,我们就可以使程序能够识别验证码(当然,也可以通过打码平台进行验证码的识别)</p> <p>示例:对如下图片进行识别</p> <div class="image-package"> <div class="image-container" style="max-width: 413px; max-height: 342px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/36d3f32448ae4bfeb22f263c42eb8e47.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/36d3f32448ae4bfeb22f263c42eb8e47.jpg" width="413" height="342" alt="Python67-爬虫_第20张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <pre><code class="python">import pytesseract from PIL import Image img_url = "verify_code.jpg" pytesseract.pytesseract.tesseract_cmd = r'D:\Tesseract-OCR\tesseract.exe' image = Image.open(img_url) print(pytesseract.image_to_string(image)) """ 使用过程中的问题: 1. 电脑上必须先安装tesseract客户端,然后才能结合pytesseract使用 2. 将tesseract加入环境变量 3. 在环境变量中新建项:名字:TESSDATA_PREFIX,值:你的tesseract的安装目录(tessdata的父级目录) 4. 在代码中加入:pytesseract.pytesseract.tesseract_cmd = r"tesseract的安装路径\tesseract.exe" 5. 默认只识别英语,如果要识别其他语言,需要下载相关语言的.traneddata文件到Tesseract的安装目录下的tessdata路径下:https://github.com/tesseract-ocr/tesseract/wiki/Data-Files """ """识别结果如下: Happy Birthday """ </code></pre> <hr> <h1>Mongodb</h1> <p>注意:以下用到的集合大多为stu(学生信息),少部分为products</p> <h2>基础入门</h2> <p>Mongodb是一种NoSQL数据库</p> <p>mysql的扩展性差,大数据下IO压力大,表结构更改困难;而nosql易扩展,大数据量高性能,灵活的数据模型,高可用</p> <p>下载地址:https://www.mongodb.com/download-center/community</p> <p><strong>mongodb的使用</strong></p> <ul> <li> <p>在终端运行<code>MongoDB\bin\mongod.exe --dbpath D:\MongoDB\data</code>,其中,D:\MongoDB是安装路径,(注意:下图中我在安装时把MongoDB写成了MonggoDB</p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 348px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/9d3ddcb1a40c4fa89123ff99633ddbe3.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/9d3ddcb1a40c4fa89123ff99633ddbe3.jpg" width="650" height="236" alt="Python67-爬虫_第21张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <ul> <li>因为在安装时我们默认安装了MongoDB Compass Community,我们打开该软件,直接连接即可,不用对其做任何更改,成功后如图所示:</li> </ul> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 381px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/018a70f3e9174b77916c6f5dab313d80.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/018a70f3e9174b77916c6f5dab313d80.jpg" width="650" height="339" alt="Python67-爬虫_第22张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <ul> <li>如果我们要使用数据库,还需要将安装目录下小bin目录加入系统的环境变量,然后在终端输入mongo即可</li> </ul> </li> </ul> <p>ps:在mongo的交互环境中,可以通过tab键进行命令的补全</p> <p><strong>database的基础命令</strong></p> <ul> <li>查看当前数据库:db</li> <li>查看所有的数据库:show dbs或show databases</li> <li>切换数据库:use db_name</li> <li>删除当前数据库:db.dropDatabase()</li> </ul> <p>在mongodb里面,是没有表的概念的,数据是存储在集合中</p> <p>向不存在的集合中第一次插入数据时,集合会被创建出来</p> <p>手动创建集合:</p> <ul> <li>db.createCollection(name,options)</li> <li>options是一个字典,例如:{size:10, capped:true} #表示存储的上限为10条数据,capped为true表示当数据达到上限时,会覆盖之前的数据</li> </ul> <ul> <li>查看集合:show collections</li> <li>删除集合:db.collection_name.drop()</li> </ul> <p><strong>mongodb中的数据类型</strong></p> <ul> <li>ObjectID:文档id,所谓文档,即我们即将存储到数据库中的一个个的字典</li> <li>String</li> <li>Boolean:必须是小写,true或false</li> <li>Integer</li> <li>Double</li> <li>Arrays</li> <li>Object:用于嵌入式的文档,即一个值为一个文档</li> <li>Null</li> <li>Timestamp:时间戳</li> <li>Date:创建日期的格式:new Date("2019-02-01")</li> </ul> <p>注意点:</p> <ul> <li>每个文档的都有一个属性,为_id,保证文档的唯一性</li> <li>可以自己设置_id插入文档,如果没有提供,自动生成,类型为Object_id</li> <li>objecID是一个12字节的16进制数,4:时间戳,3:机器id,2:mongodb的服务进程id,3:简单的增量值</li> </ul> <p><strong>数据的操作</strong></p> <ul> <li>用insert插入:先use数据库,<code>db.集合名.insert({"name":"zhang3", "age":23})</code>,实质上插入的数据不是字典,而是json,因此键可以不用引号。insert的时候如果文档id已经存在,会报错</li> <li>查看表中的数据:<code>db.表名.find()</code> </li> <li>用save进行数据的插入:<code>db.集合名.save(要插入的数据)</code>,如果文档id(对应我们要插入的数据)已经存在,就是修改,否则新增</li> <li>查看集合中的数据:<code>db.集合名称.find()</code> </li> <li>更新:db.集合名称.<code>update(<query>,<update>,{multi:<boolean>})</code>,用法如下: <pre><code class="python">db.stu.upate({name:'hr'}, {name:'mnc'})#更新一条的全部 db.stu.update({name:'hr'}, {$set:{name:'mnc'}}) #更新一条中的对应键值 """这种更改用得更多""" db.stu.update({},{$set:{gender:0}}, {multi:true}) #更新全部 """注意:multi这个参数必须和$符号一起使用才有效果""" </code></pre> </li> <li>使用remove删除数据:db.集合名.remove({name:"zhang3"},{justOne:true}),表示只删除一条名字为zhang3的数据,如果不指定justOne,就是删除全部符合的数据</li> </ul> <h2>高级查询</h2> <p><strong>find</strong></p> <pre><code class="python">"""find""" db.stu.find() #查询所有的数据 db.stu.find({age:23}) #查询满足条件的数据 db.stu.findOne({age:23}) #查询满足条件的一个数据 db.stu.find().pretty() #对数据进行美化 </code></pre> <p><strong>比较运算符</strong></p> <pre><code class="python">1. 等于:默认是等于判断,没有运算符 2. 小于:$lt(less than) 3. 大于:$gt(greater than) 4. 小于等于:$lte(less than equal) 5. 大于等于:$gte(greater than equal) 6. 不等于:$ne(not equal) </code></pre> <p>使用举例:</p> <pre><code class="python">db.stu.find({age:{$le(18)}}) #查询年龄小于18的 </code></pre> <p><strong>范围运算符</strong></p> <pre><code class="python">1. $in:在某个范围 2. $nin:不在某个范围 </code></pre> <p>用法举例:</p> <pre><code class="python">db.stu.find({age:{$in[18,28,38]}}) #查询年龄为18或28或38的 </code></pre> <p><strong>逻辑运算符</strong></p> <pre><code class="python">and:直接写多个条件即可,例:db.stu.find({age:{$gte:18},gender:true}) or:使用$or,值为数组,数组中的每个元素为json,例:查询年龄大于18或性别为false的数据:db.stu.find({$or:[{age:{$gt:18}},{gender:{false}}]}) </code></pre> <p><strong>正则表达式</strong></p> <pre><code class="python">1. db.products.find({sku:/^abc/}) #查询以abc开头的sku 2. db.products.find({sku:{$regex:"789$"}}) #查询以789结尾的sku </code></pre> <p><strong>limit和skip</strong></p> <pre><code class="python">1. db.stu.find().limit(2) #查询两个学生的信息 2. db.stu.find().skip(2) #跳过前两个学生的信息 3. db.stu.find().skip(2).limit(4) #先跳过2个,再查找4个 </code></pre> <p><strong>自定义查询</strong></p> <pre><code class="python">db.stu.find({$where:function(){ return this.age > 30; }}) #查询年龄大于30的学生 </code></pre> <p><strong>投影</strong></p> <p>即返回满足条件的数据中的部分内容,而不是返回整条数据</p> <pre><code class="python">db.stu.find({$where:function(){ return this.age > 30, {name:1,hometown:1}; }}) #查询年龄大于30的学生,并返回其名字和hometown,其中,this是指从前到后的每一条数据;如果省略{name:xxx}就会返回该条数据的全部内容 db.stu.find({},{_id:0,name:1,hometown:1}) #显示所有数据的name和hometown,不显示_id,但是要注意,只有_id可以使用0;一般对其他字段来说,要显示的写1,不显示的不写即可,_id默认是会显示的 </code></pre> <p><strong>排序</strong></p> <pre><code class="python">db.stu.find().sort({age:-1}) #按年龄的降序排列,如果是{age:1}就是按按铃升序排序 db.stu.find().sort({age:1,gender:-1}) #按年龄的升序排列,如果年龄相同,按gender的降序排列 </code></pre> <p><strong>count方法</strong></p> <pre><code class="python">db.stu.find({条件}).count() #查看满足条件的数据有多少条 db.stu.count({条件}) </code></pre> <p><strong>消除重复</strong></p> <pre><code class="python">db.stu.distinct("去重字段",{条件}) db.stu.distinct("hometown",{age:{$gt:18}}) #查看年龄大于18的人都来自哪几个地方 </code></pre> <h2>聚合aggregate</h2> <p>聚合(aggregate)是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。<br> db.集合名称.aggregate({管道:{表达式}})</p> <p>所谓管道,即把上一次的输出结果作为下一次的输入数据</p> <p><strong>常用管道如下</strong>:</p> <ul> <li>$group: 将集合中的⽂档分组, 可⽤于统计结果</li> <li>$match: 过滤数据, 只输出符合条件的⽂档,match:匹配</li> <li>$project: 修改输⼊⽂档的结构, 如重命名、 增加、 删除字段、 创建计算结果</li> <li>$sort: 将输⼊⽂档排序后输出</li> <li>$limit: 限制聚合管道返回的⽂档数</li> <li>$skip: 跳过指定数量的⽂档, 并返回余下的⽂档</li> <li>$unwind: 将数组类型的字段进⾏拆分,即展开的意思</li> </ul> <p><strong>表达式</strong></p> <p>语法:表达式:'$列名'<br> 常⽤表达式:</p> <ul> <li> sum:1 表示以⼀倍计数</li> <li>$avg: 计算平均值</li> <li>$min: 获取最⼩值</li> <li>$max: 获取最⼤值</li> <li>$push: 在结果⽂档中插⼊值到⼀个数组中</li> <li>$first: 根据资源⽂档的排序获取第⼀个⽂档数据</li> <li>$last: 根据资源⽂档的排序获取最后⼀个⽂档数据</li> </ul> <p><strong>用法示例</strong>:</p> <pre><code class="python">"""group的使用""" db.Temp.aggregate( {$group:{_id:"$gender"}} ) #按性别分组 """输出结果: { "_id" : 1 } { "_id" : 0 } """ db.Temp.aggregate( {$group:{_id:"$gender",count:{$sum:1}}} ) #按性别分组并计数,sum:1是指每条数据作为1 """输出结果如下: { "_id" : 1, "count" : 7 } { "_id" : 0, "count" : 1 } """ """注意:_id和count的键不能变""" db.Temp.aggregate( {$group:{_id:"$gender", count:{$sum:1}, avg_age:{$avg:"$age"}}} ) #按年龄分组并计数,再分别计算其年龄的平均值 """结果如下: { "_id" : 1, "count" : 7, "avg_age" : 22.857142857142858 } { "_id" : 0, "count" : 1, "avg_age" : 32 } """ """注意:如果分组时_id:null,则会将整个文档作为一个分组""" """管道的使用""" db.Temp.aggregate( {$group:{_id:"$gender",count:{$sum:1},avg_age:{$avg:"$age"}}}, {$project:{gender:"$_id",count:"$count",avg_age:"$avg_age"}} ) #将group的输出再作为project的输入,因为前面已经有了_id,count,avg_age等输出键,所以在后面的管道中可以直接使用(此例中用了_id和avg_age),也可以使用1使其显示,0使其不显示 """输出结果如下 { "count" : 7, "gender" : 1, "avg_age" : 22.857142857142858 } { "count" : 1, "gender" : 0, "avg_age" : 32 } """ """match管道的使用""" #为什么使用match过滤而不是find的过滤?match可以将其数据交给下一个管道处理,而find不行 db.Temp.aggregate( {$match:{age:{$gt:20}}}, {$group:{_id:"$gender",count:{$sum:1}}}, {$project:{_id:0,gender:"$_id",count:1}} ) #先选择年龄大于20的数据;然后将其交给group管道处理,按照性别分组,对每组数据进行计数;然后再将其数据交给project处理,让_id字段显示为性别,不显示_id字段,显示count字段 """sort管道的使用""" db.Temp.aggregate( {$group:{_id:"$gender",count:{$sum:1}}}, {$sort:{count:-1}} ) #将第一个管道的数据按照其count字段的逆序排列,和find中的排序使用方式一样 """结果如下: { "_id" : 1, "count" : 7 } { "_id" : 0, "count" : 1 } """ """skip和limit的用法示例: {$limit:2} {$skip:5} """ """unwind使用使例:""" eg:假设某条数据的size字段为:['S','M','L'],要将其拆分 db.Temp.aggregate( {$match:{size:["S","M","L"]}}, #先找到该数据 {$unwind:"$size"} ) """结果如下: { "_id" : ObjectId("5d57cada783675188ccd7ee0"), "size" : "S" } { "_id" : ObjectId("5d57cada783675188ccd7ee0"), "size" : "M" } { "_id" : ObjectId("5d57cada783675188ccd7ee0"), "size" : "L" } """ </code></pre> <p>小练习:</p> <pre><code class="python">"""数据和需求: { "country" : "china", "province" : "sh", "userid" : "a" } { "country" : "china", "province" : "sh", "userid" : "b" } { "country" : "china", "province" : "sh", "userid" : "a" } { "country" : "china", "province" : "sh", "userid" : "c" } { "country" : "china", "province" : "bj", "userid" : "da" } { "country" : "china", "province" : "bj", "userid" : "fa" } 需求:统计出每个country/province下的userid的数量(同一个userid只统计一次) """ db.Exci.aggregate( {$group:{_id:{userid:"$userid",province:"$province",country:"$country"}}}, #先按照三个字段分组(去重) {$group:{_id:{country:"$_id.country",province:"$_id.province"},count:{$sum:1}}}, {$project:{_id:0,country:"$_id.country",province:"$_id.province",count:"$count"}} ) """注意:取字典里面的元素用(.)操作符;group的_id可以为字典""" """三个管道处理过后的数据分别如下: #第一次group { "_id" : { "userid" : "a", "province" : "sh", "country" : "china" } } { "_id" : { "userid" : "b", "province" : "sh", "country" : "china" } } { "_id" : { "userid" : "c", "province" : "sh", "country" : "china" } } { "_id" : { "userid" : "da", "province" : "bj", "country" : "china" } } { "_id" : { "userid" : "fa", "province" : "bj", "country" : "china" } } #第二次group { "_id" : { "country" : "china", "province" : "bj" }, "count" : 2 } { "_id" : { "country" : "china", "province" : "sh" }, "count" : 3 } #最终结果 { "country" : "china", "province" : "sh", "count" : 3 } { "country" : "china", "province" : "bj", "count" : 2 } """ """也可以写成如下形式:""" db.Temp.aggregate( {$match:{size:["S","M","L"]}}, {$unwind:{path:"$size",preserveNullAndEmptyArrays:true}} ) #path字段是要拆分的字段,参数表示保存Null和EmptyArrays,因为如果是原数据中有某字段为null或[],那么在拆分一个数据后,表中原来含nul或[]的那几条数据会消失 </code></pre> <h2>索引</h2> <p>作用:提升查询速度</p> <p>db.t1.find({查询条件})<br> db.t1.find({查询条件}).explain('executionStats') 可以通过其中的"executionTimeMillisEstimate"字段查看查询所花费的时间</p> <p><strong>建立索引</strong></p> <ul> <li><p>语法:db.集合.ensureIndex({属性1:1}, {unique:true}) 其中,1表示升序,-1表示降序,一般来说,升序或降序的影响不大;unique字段可以省略,加上后,保证索引唯一,即:如果我们用name作为索引,那么在集合中就不能有name值相同的数据;</p></li> <li><p>联合索引,即ensureIndex的参数为{属性1:1或-1, 属性2:-1或1},联合索引是为了保证数据的唯一性</p></li> <li><p>唯一索引的作用:比如,当我们爬取数据时,如果使用了唯一索引,那么,当我们爬到重复数据时,就不会存储到数据库中</p></li> <li><p>默认有一个index:_id</p></li> <li><p>查看索引:db.集合.getIndex()</p></li> <li><p>删除索引:db.集合.dropIndex("索引名称") #索引名称即我们创建索引时传入的字典{属性:1或-1},可以通过getIndex()查看时的key项</p></li> </ul> <h2>爬虫数据去重,实现增量式爬虫</h2> <ul> <li><p>使用数据库建立唯一索引进行去重</p></li> <li> <p>url地址去重</p> <ul> <li> <p>使用场景</p> <ul> <li>如果url对应的数据不会变,url地址能够唯一的判别一条数据的情况</li> </ul> </li> <li> <p>思路</p> <ul> <li>url地址存在redis中</li> <li>拿到url地址,判断url地址在url的集合中是否存在</li> <li>存在:不再请求</li> <li>不存在:请求,并将该url地址存储到redis数据库中</li> </ul> </li> <li> <p>布隆过滤器</p> <ul> <li>使用加密算法加密url地址,得到多个值</li> <li>往对应值的位置把结果设置为1</li> <li>新来一个url地址,一样通过加密算法生成多个值</li> <li>如果对应位置的值全为1,说明这个url已经被抓过</li> <li>否则没有被抓过,就把对应位置的值设置为1</li> </ul> </li> </ul> </li> <li> <p>根据数据本身去重</p> <ul> <li>选择特定字段,使用加密算法(md5,shal)将字段进行加密,生成字符串,存入redis集合中</li> <li>如果新来一条数据,同样的方法进行加密,如果得到的数据在redis中存在,说明数据存在,要么插入,要么更新,否则不存在,直接插入</li> </ul> </li> </ul> <h2>数据的备份与恢复</h2> <p><strong>备份的语法</strong>:<br> mongodump -h dbhost -d dbname -o dbdirectory<br> -h: 服务器地址, 也可以指定端⼝号,如果是本机上,就可以省略<br> -d: 需要备份的数据库名称<br> -o: 备份的数据存放位置, 此⽬录中存放着备份出来的数据</p> <p>备份的数据中,一个json和一个bson表示一个集合</p> <p><strong>恢复的语法</strong>:<br> mongorestore -h dbhost -d dbname --dir dbdirectory<br> -h: 服务器地址<br> -d: 需要恢复的数据库实例,即数据库的名字<br> --dir: 备份数据所在位置</p> <hr> <h1>pymongo的使用</h1> <p>pip install pymongo<br> from pymongo import MongoClient</p> <p><strong>用法示例</strong></p> <pre><code class="python">from pymongo import MongoClient client = MongoClient(host='127.0.0.1',port=27017) #实例化client,即和数据库建立连接 collection = client['admin']['Temp'] #使用[]选择数据库和集合 collection.insert_one({"name":"laowang","age":33}) #插入一条数据 it_data = [{"name":"laoli","age":23},{"name":"laozhao","age":43}] collection.insert_many(it_data) #插入多条数据 print(collection.find_one({"name":"laoli"})) print(collection.find()) #是一个Cursor(游标)对象,一个Cursor对象只能进行一次遍历 for ret in collection.find(): print(ret) #遍历查看cursor对象 print(list(collection.find())) #强制转化为list collection.delete_one({"name":"laoli"}) #删除一个 collection.delete_many({"age":33}) #删除所有age为33的 # mongodb不需要我们手动断开连接 </code></pre> <hr> <h1>scrapy</h1> <h2>scrapy简介</h2> <p>为什么要使用scrapy:使我们的爬虫更快更强</p> <p>scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架</p> <p>scrapy使用了Twisted异步网络框架,可以加快我们的下载</p> <p><strong>scrapy的工作流程</strong></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 489px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/a7bae3fdd4634317ab693f0617191b7e.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/a7bae3fdd4634317ab693f0617191b7e.jpg" width="650" height="384" alt="Python67-爬虫_第23张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <p>scheduler里面实际上存放的并不是url地址,而是request对象</p> <p>在spiders处,url要先组装成request对象再交到scheduler调度器</p> <p>scrapy引擎的作用:scheduler将request交给scrapy engine,engine再交给下载器,response也是先由下载器交给scrapy engine,然后再由engine交给spiders,url类似,先交给scrapy engine,再交给scheduler</p> <p>engine实现了程序的解耦,response和request在经过scrapy后,还要经过各自的middleware,再交到目的地,因此我们就可以定义自己的中间件,对reponse和request进行一些额外的处理</p> <p>爬虫中间件不会对爬虫提取的数据进行数据(实际上可以,但是因为有专门的部分进行这项工作,所以我们通常不这么做)</p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 466px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/0c294bb5d151422cb3b53d774bd984fc.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/0c294bb5d151422cb3b53d774bd984fc.jpg" width="650" height="418" alt="Python67-爬虫_第24张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <h2>scrapy入门</h2> <ul> <li> <p>创建一 个scrapy项目:scrapy startproject 项目名(eg:myspider)</p> <br> <div class="image-package"> <div class="image-container" style="max-width: 555px; max-height: 376px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/6a31b37649c6424a84a93d86c984c6ce.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/6a31b37649c6424a84a93d86c984c6ce.jpg" width="555" height="376" alt="Python67-爬虫_第25张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> </li> <li><p>生成一个爬虫:scrapy genspider 爬虫名字 "允许爬取的域名"</p></li> <li> <p>提取数据</p> <ul> <li>完善spider,使用xpath等方法</li> </ul> </li> <li> <p>保存数据</p> <ul> <li>pipline中保存数据</li> </ul> </li> </ul> <h2>scrapy具体流程及spider和pipline讲解</h2> <p>此处的项目名为mySpider,创建的爬虫名字为itcast</p> <ul> <li><p>新建一个python项目</p></li> <li><p>在Terminal中:scrapy startproject mySpider</p></li> <li><p>在Terminal中,根据提示:cd mySpider</p></li> <li> <p>在Terminal中:scrapy genspider itcast "itcast.cn",此时,如果创建成功,就会在spiders目录中有了itcast.py;在里面,我们写上如下代码段内容:</p> <ul> <li> <p>在项目文件夹中使用scrapy新建的爬虫都在spider文件夹中,每个spider文件即对应上面流程图中的spiders,其中有几个默认字段:</p> <ul> <li>name:爬虫的名字,默认有</li> <li>allowed_domains:默认有(在使用scrapy新建spider的时候通常会指定)</li> <li>start_urls:默认有,但是通常需要我们自己修改,其值为我们最开始请求的url地址</li> <li>parse方法:处理start_url对应的响应地址,通过yield将我们提取到的数据传递到pipline</li> </ul> </li> </ul> <pre><code class="python">import scrapy class ItcastSpider(scrapy.Spider): name = 'itcast' #爬虫名 allowed_domains = ['itcast.cn'] #允许爬取的范围 start_urls = ['http://www.itcast.cn/channel/teacher.shtml'] #最开始请求的url地址 def parse(self, response): """处理start_url对应的响应""" # ret1 = respnse.xpath("//div[@class='tea_con']//h3/text()").extract() # #提取数据 # #extract()方法可以提取其中的文字 # print(ret1) li_list = response.xpath("//div[@class='tea_con']//li") for li in li_list: item = {} item['name'] = li.xpath(".//h3/text()").extract_first() #提取第一个字符串 #使用extract_first,如果是没有拿到元素,会返回none,而不是报错(extract()[0]在拿不到元素的情况下会报错) item['title'] = li.xpath(".//h4/text()").extract_first() yield item #将item传给piplines </code></pre> </li> <li><p>在Terminal中,进入项目文件夹下:scrapy crawl itcast,就会自动开始爬取;然后在terminal中输出一些结果和一些日志,我们可以在settings.py中对日志的级别进行设置,比如添加:LOG_LEVEL = "WARNING",比warning等级小的日志都不会输出</p></li> <li> <p>pipline的使用</p> <ul> <li><p>pipline对应流程图中的item pipline</p></li> <li> <p>要使用pipline,需要在项目的settings.py文件中取消对pipline的注释,使其可用,即</p> <pre><code class="python"># Configure item pipelines # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html ITEM_PIPELINES = { 'mySpider.pipelines.MyspiderPipeline': 300, #意为:mySpider项目下的piplines模块中的MyspiderPipline类,后面的数字(300)表示距离引擎的远近,越近,数据就会越先经过该pipline #所谓管道,就是把前面管道处理后的数据再交给后面的管道处理,这里ITEM_PIPLINES的格式为字典:管道类的位置:距离引擎的远近 #把spiders提取的数据由近及远交给各个管道处理 #亦即:我们可以在piplines中定义自己的多个管道,然后在这里进行注册,使其可用,如下 'mySpider.pipelines.MyspiderPipeline1': 301, } </code></pre> </li> </ul> </li> <li><p>执行爬虫爬取数据:scrapy crawl 爬虫的名字(类下面的name的值)</p></li> <li> <p>在piplines.py中,我们定义了如下的两个管道</p> <ul> <li>为了让数据能够在各个管道间进行传递,每个管道必须return item,这里的item即为spider中传递过来的数据</li> <li>process_item方法是必须的,专门用于对数据的处理,只有它可以接受传递过来的item</li> <li>spider就是爬虫在传item的时候,把自己也传递过来了,即:这里的参数spider就是我们在spiders目录下的爬虫名的py文件中定义的spider类</li> </ul> <pre><code class="python">class MyspiderPipeline(object): def process_item(self, item, spider): print(item) return item class MyspiderPipeline1(object): def process_item(self, item, spider): print(item.items()) return item </code></pre> </li> <li> <p>为什么需要有多个pipline</p> <ul> <li>一个项目通常有多个爬虫,而对于爬取的数据,我们通常要进行的处理不相同,因此就需要使用不同的pipline <ul> <li>此时需要对传过来的item进行判别,比如可以使用在item中添加某字段以判别(或者使用spider进行判别,比如:if spider.name == xxx),如果是我们要处理的数据才进行处理,否则传递给其他pipline</li> </ul> </li> <li>一个spider的内容可能要做不同的操作,比如存入不同的数据库中,我们就可以使用多个pipline分多步进行</li> </ul> </li> </ul> <h2>logging模块的使用</h2> <p>在settings.py文件中,可以添加字段:LOG_LEVEL="log等级",以控制当前爬虫的输出的log等级(大于)</p> <p>在spider中输出log的两种常用方法:</p> <ul> <li><p><code>import logging</code>,然后使用<code>logging.warning(要输出的信息)</code>,无法显示log来自哪个文件</p></li> <li> <p><code>impot logging</code>,然后<code>logger = logging.getLogger(__name__)</code>,使用<code>logger.warning(要输出的数据)</code>,此种方法可以输出日志来自哪个文件</p> <ul> <li>ps:我们实例化了一个logger之后,在其他的文件中如果要使用log,不必单独再去实例化一个对象,直接导入现有的logger即可</li> </ul> </li> </ul> <p>如果我们要想使log输出到文件中,而非terminal,则需要在settings.py中添加字段:LOG_FILE = "保存log的文件路径"</p> <p>如果要自定义log的格式,在使用logging前:logging.basicConfig(xxx),其中的xxx即我们要自定义的log格式<br> logging.basicConfig()示例:</p> <pre><code class="python">import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filemode='w') </code></pre> <pre><code class="python">"""basicConfig参数""" logging.basicConfig函数各参数: filename: 指定日志文件名 filemode: 和file函数意义相同,指定日志文件的打开模式,'w'或'a' format: 指定输出的格式和内容,format可以输出很多有用信息,如上例所示: %(levelno)s: 打印日志级别的数值 %(levelname)s: 打印日志级别名称 %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0] %(filename)s: 打印当前执行程序名 %(funcName)s: 打印日志的当前函数 %(lineno)d: 打印日志的当前行号 %(asctime)s: 打印日志的时间 %(thread)d: 打印线程ID %(threadName)s: 打印线程名称 %(process)d: 打印进程ID %(message)s: 打印日志信息 datefmt: 指定时间格式,同time.strftime() level: 设置日志级别,默认为logging.WARNING stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略 </code></pre> <h2>翻页请求</h2> <ul> <li>在爬虫中,首先,获得下一页的url:<code>next_url = response.xpath("//a[text()='下一页']/@href").extract()</code>以获得下一页的url</li> <li>然后使用scrapy.Request构造一个request,同时指定回调函数</li> <li>在回调函数中,对于要pipline处理的数据,同样要yield <pre><code class="python">while next_url: yield scrapy.Request(next_url, callback=self.parse) #如果下一页数据的处理和当前页相同,那么回调函数就直接指定当前函数即可,如果处理方式,则另外定义一个函数进行回调即可;这里实际上也是实例化了一个request对象交给引擎 </code></pre> </li> </ul> <p><strong>scrapy.request的其他知识点</strong></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 260px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/16372277dc9d4f5487b70736ba4bee52.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/16372277dc9d4f5487b70736ba4bee52.jpg" width="650" height="200" alt="Python67-爬虫_第26张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <ul> <li>如图所示,在crapy中,cookies就不能再放到headers中去</li> <li>所谓解析函数,可以简单理解为回调函数,meta的格式为字典,在解析函数中获取该数据时:response.meta["键"]</li> </ul> <p><strong>设置user-agent</strong></p> <ul> <li>user-agent的使用:在项目的设置文件中找到对应项进行设置即可</li> </ul> <p><strong>案例(结合下面的item)</strong></p> <p>爬取阳光热线问政平台:</p> <pre><code class="python"># -*- coding: utf-8 -*- import scrapy from yangguang.items import YangguangItem class YgSpider(scrapy.Spider): name = 'yg' allowed_domains = ['sun0769.com'] start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=0'] def parse(self, response): tr_list = response.xpath("//div[@class='greyframe']/table[2]/tr/td/table/tr") for tr in tr_list: item = YangguangItem() item['title'] = tr.xpath("./td[2]/a[@class='news14']/@title").extract_first() item['href'] = tr.xpath("./td[2]/a[@class='news14']/@href").extract_first() item['publish_data'] = tr.xpath("./td[last()]/text()").extract_first() yield scrapy.Request( item['href'], callback= self.parse_detail, meta={"item":item} ) next_url = response.xpath("//a[text()='>']/@href").extract_first() if next_url: yield scrapy.Request( next_url, callback=self.parse ) def parse_detail(self,response): """处理详情页""" item = response.meta['item'] item['content'] = response.xpath("//td[@class='txt16_3']//text()").extract_first() item['content_img'] = response.xpath("//td[@class='txt16_3']//img/@src").extract() yield item </code></pre> <h2>scrapy深入</h2> <h3>Items</h3> <p>使用流程:</p> <ul> <li> <p>先在items.py中写好我们要使用的字段,如图:</p> <br> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 165px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/bef838c1f24142179ed98ffc4a3c1e43.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/bef838c1f24142179ed98ffc4a3c1e43.jpg" width="650" height="141" alt="Python67-爬虫_第27张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <ul> <li>说明:就相当于我们定义了一个字典类,规定好了里面可以有的键,以后如果使用这个字典的实例时,发现想往里面存入未定义的键,程序就会报错</li> </ul> </li> <li><p>使用时,在spider中导入该类(这里是Myspideritem),然后用其实例化一个对象(当作字典使用即可)</p></li> <li> <p>然后通常是用这个字典存储我们提取的数据,然后把其在各个piplines间传递</p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 261px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/679b437aadb0426ab5096b9d3e61812b.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/679b437aadb0426ab5096b9d3e61812b.jpg" width="650" height="214" alt="Python67-爬虫_第28张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> </li> <li><p><code>注意:</code>item对象不能直接插入mongodb(只是像字典,毕竟不是字典),可以强制将其转化为字典,然后存入即可</p></li> <li><p>ps:对不同爬虫爬取的数据,我们可以定义多个item类,然后在pipline中处理时,可以用isinstance判断是否为某个item类的实例,如果是,我们才处理</p></li> </ul> <h3>debug信息</h3> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 293px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/7f78b002167344aea775298c2f9bbf12.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/7f78b002167344aea775298c2f9bbf12.jpg" width="650" height="221" alt="Python67-爬虫_第29张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <h3>scrapy shell</h3> <p>Scrapy shell是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath表达式</p> <p>使用方法:<br> scrapy shell http://www.itcast.cn/channel/teacher.shtml</p> <p>就会自动进入shell,在shell中进行一些操作,会自动提示<br> 然后就能得到response</p> <p>response:</p> <ul> <li>response.url:当前响应的url地址</li> <li>response.request.url:当前响应对应的请求的url地址</li> <li>response.headers:响应头</li> <li>response.body:响应体,也就是html代码,默认是byte类型</li> <li>response.requests.headers:当前响应的请求头</li> <li>response.xpath()</li> </ul> <p>spider:</p> <ul> <li>spider.name</li> <li>spider.log(log信息)</li> </ul> <h3>settings</h3> <p><strong>settings中的字段</strong></p> <p>默认已有字段:</p> <ul> <li>bot_name:项目名</li> <li>spider_modules:爬虫位置</li> <li>newspider_module:新建爬虫的位置</li> <li>user-agent:用户代理</li> <li>robotstxt_obey:是否遵守robot协议</li> <li>CONCURRENT_REQUESTS:并发请求的最大数量</li> <li>DOWNLOAD_DELAY:下载延迟</li> <li>CONCURRENT_REQUESTS_PER_DOMAIN:每个域名的最大并发请求数</li> <li>CONCURRENT_REQUESTS_PER_IP:每个代理ip的最大并发请求数</li> <li>COOKIES_ENABLED:是否开启cookies</li> <li>TELNETCONSOLE_ENABLED:是否启用teleconsole插件</li> <li>DEFAULT_REQUEST_HEADERS:默认请求头</li> <li>spider_midddleware:爬虫中间件</li> <li>downlowd_middleware:下载中间件</li> <li>EXTENSIONS:插件</li> <li>ITEM_PIPELINES:管道,其格式为:<code>管道的位置:权重</code> </li> <li>AUTOTHROTTLE_ENABLED:自动限速</li> <li>缓存的配置项</li> </ul> <p>可自己添加字段:</p> <ul> <li>LOG_LEVEL</li> </ul> <p>在其他位置中要使用配置中的数据:</p> <ol> <li>法一:直接导入settings模块使用</li> <li>如果是在spider中:可以直接用self.settings.get()或是self.settings[]以字典的形式存取相关数据</li> <li>如果是在pipline中,由于传过来了spider,就以spider.settings.get()或spider.settings[]存取</li> </ol> <h3>piplines</h3> <pre><code class="python">import json class myPipline(object): def open_spider(self,spider): """在爬虫开启的时候执行一次""" #比如实例化MongoClient pass def close_spider(self,spider): """在爬虫关闭的时候执行一次""" pass def process_item(self,item,spider): """对spider yield过来的数据进行处理""" pass return item """如果不return item,其他的pipline就无法获得该数据""" </code></pre> <h2>CrawlSpider</h2> <p>之前爬虫的思路:<br> 1、从response中提取所有的a标签对应的url地址<br> 2、自动的构造自己requests请求,发送给引擎</p> <p>改进:</p> <p>满足某个条件的url地址,我们才发送给引擎,同时能够指定callback函数</p> <p>如何生成crawlspider:<br> eg:<br> scrapy genspider –t crawl csdn “csdn.com"</p> <p>crawlspider示例:</p> <pre><code class="python">from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule import re class CfSpider(CrawlSpider): #继承的父类不再是scrapy.spider name = 'cf' allowed_domains = ['circ.gov.cn'] start_urls = ['http://circ.gov.cn/web/site0/tab5240/module14430/page1.htm'] """定义提取url规则的地方""" """每个Rule是一个元组""" """注意:每个url提取出来后被构造成一个请求,他们没有先后顺序""" rules = ( #Rule是一个类,LinkExtractor: 链接提取器,其参数是一个正则表达式,提取到了link,就交给parse函数进行请求 #所以我们在crawlspider中不能自己定义parse函数 #url请求的响应数据会交给callback处理,如果不用提取该url中的数据,就可以不指定callback #follow,当前url地址的相应是否重新进入rules来提取url地址(会挨个按规则提取,如果被前面的正则表达式匹配到了,就不会再被后面的进行匹配提取,所以写正则表达式的时候应该尽可能明确) #注意:crawlspider能够帮助我们自动把链接补充完整,所以我们下面的allow中并没有手动补全链接 Rule(LinkExtractor(allow=r'/web/site0/tab5240/info\d+.htm'), callback='parse_item', follow=False), Rule(LinkExtractor(allow=r'/web/site0/tab5240/module14430/page\d+.htm'), follow=True), ) """parse函数不见了,因为其有特殊功能,不能定义""" def parse_item(self, response): """解析函数""" item = {} #item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get() #item['name'] = response.xpath('//div[@id="name"]').get() #item['description'] = response.xpath('//div[@id="description"]').get() item['title'] = re.findall(r"<!--TitleStart-->(.*?)<!--TitleEnd-->",response.body.decode())[0] item['date'] = re.findall(r"发布时间:(\d{4}-\d{2}-\d{2})",response.body.decode()) print(item) # 也可以自己再yiel scrapy.Request # yield scrapy.Request( # url, # callback=self.parse_detail, # meta={"item":item} # ) # # def parse_detail(self,response): # item = response.meta['item'] # pass # yield item </code></pre> <p><strong>LinkExtractor和Rule的更多知识点</strong></p> <div class="image-package"> <div class="image-container" style="max-width: 700px; max-height: 471px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/89ea9a72f7c64202a9e4cee3dd83097f.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/89ea9a72f7c64202a9e4cee3dd83097f.jpg" width="650" height="410" alt="Python67-爬虫_第30张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <h2>中间件</h2> <h3>下载中间件</h3> <p>下载中间件是我们要经常操作的一个中间件,因为我们常常需要在下载中间件中对请求和响应做一些自定义的处理</p> <p>如果我们要使用中间件,需要在settings中开启,其格式也是:位置:权重(或者说是距离引擎的位置,越小越先经过)</p> <p><strong>Downloader Middlewares默认的方法</strong>:</p> <ul> <li>process_request(self, request, spider):<br> 当每个request通过下载中间件时,该方法被调用。</li> <li>process_response(self, request, response, spider):<br> 当下载器完成http请求,传递响应给引擎的时候调用</li> </ul> <p>案例:使用随机user-agent:</p> <p>在settings.py中定义USER_AGENTS_LIST:</p> <pre><code class="python">USER_AGENTS_LIST = ['Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0', ] </code></pre> <p>在middlewares.py中定义下载中间件:</p> <pre><code class="python">import random class RandomUserAgentMiddleware: """自定义一个下载中间件""" def process_request(self,request,spider): ua = random.choice(spider.settings.get("USER_AGENTS_LIST")) request.headers["User-Agent"] = ua #request.meta['proxy'] = "你的proxy" #也可以通过此种方法来使用代理 # return request,process不能返回request class CheckUserAgentMiddleware: def process_response(selfs,request,response,spider): print(request.headers["User-Agent"]) #查看是否实现了随机用户代理 return response # process_response必须返回reponse </code></pre> <p>并在settings.py中对自己的中间件进行注册:</p> <pre><code class="python">DOWNLOADER_MIDDLEWARES = { # 'circ.middlewares.CircDownloaderMiddleware': 543, 'circ.middlewares.RandomUserAgentMiddleware': 544, 'circ.middlewares.CheckUserAgentMiddleware': 545, #这里的权重并不重要,因为他们一个是处理请求,一个是处理响应的 } </code></pre> <p>spiders内容省略</p> <h2>scrapy模拟登录</h2> <p>对于scrapy来说,有两个方法模拟登陆:<br> 1、直接携带cookie<br> 2、找到发送post请求的url地址,带上信息,发送请求</p> <h3>直接携带cookie</h3> <p>案例:爬取人人网登录后的信息</p> <pre><code class="python">import scrapy import re class RenrenSpider(scrapy.Spider): name = 'renren' allowed_domains = ['renren.com'] start_urls = ['http://www.renren.com/971962231/profile'] #人人网的个人主页 def start_requests(self): """覆盖父类的start_request方法,从而使其携带我们自己的cookies""" cookies = "我的cookies" cookies = {i.split("=")[0]:i.split("=")[1] for i in cookies.split(";")} yield scrapy.Request( self.start_urls[0], callback=self.parse, #表示当前请求的响应会发送到parse cookies=cookies ) #因为cookies默认是enable的,所以下次请求会自动拿到上次的cookies def parse(self, response): print(re.findall(r"假装",response.body.decode())) #验证是否请求成功 yield scrapy.Request( "http://www.renren.com/971962231/profile?v=info_timeline", callback=self.parse_data, ) def parse_data(self,response): """"访问个人资料页,验证cookie的传递""" print(re.findall(r"学校信息",response.body.decode())) </code></pre> <p>此外,为了查看cookies的传递过程,可以在settings中加上字段:COOKIES_DEBUG = True</p> <h3>scrapy发送post请求</h3> <p>案例:爬取github</p> <p>spider:</p> <pre><code class="python">import scrapy import re class GitSpider(scrapy.Spider): name = 'git' allowed_domains = ['github.com'] start_urls = ['https://github.com/login'] def parse(self, response): authenticity_token = response.xpath("//input[@name='authenticity_token']/@value").extract_first() utf8 = response.xpath("//input[@name='utf8']/@value").extract_first() webauthn_support = response.xpath("//input[@name='webauthn-support']/@value").extract_first() post_data = { "login":"你的邮箱", "password":"密码", "webauthn-support":webauthn_support, "authenticity_token":authenticity_token, "utf8":utf8 } print(post_data) yield scrapy.FormRequest( "https://github.com/session", #数据提交到的地址 formdata=post_data, callback=self.after_login #无论这个post请求成功没有,响应都会交给after_login ) def after_login(self,response): print(response) print(re.findall(r"Trial_Repo", response.body.decode())) #匹配我的某个仓库名,以验证是否成功 </code></pre> <p>settings中的修改字段:</p> <pre><code class="python">USER_AGENT = 'Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Mobile Safari/537.36' ROBOTSTXT_OBEY = False </code></pre> <p><strong>scrapy还可以帮我们自动从表单中提取action的地址</strong></p> <p>爬取github登录后的页面:<br> spider:</p> <pre><code class="python"># -*- coding: utf-8 -*- import scrapy import re class Github2Spider(scrapy.Spider): name = 'github2' allowed_domains = ['github.com'] start_urls = ['https://github.com/login'] def parse(self, response): post_data = { "login":"2537119279@qq.com", "password":"A1d9b961017#" } yield scrapy.FormRequest.from_response( #自动从response中寻找form表单,然后将formdata提交到对应的action的url地址 #如果有多个form表单,可以通过其他参数对表单进行定位,其他参数见源码 response, formdata=post_data, callback=self.after_login, ) def after_login(self,response): print(re.findall(r"Trial_Repo", response.body.decode())) </code></pre> <p>另:无需在settings中设置任何东西</p> <hr> <h1>scrapy_redis</h1> <ul> <li>scrapy_redis的作用:reqeust去重,爬虫持久化,和轻松实现分布式</li> </ul> <p><strong>scrapy_redis爬虫的流程</strong></p> <div class="image-package"> <div class="image-container" style="max-width: 613px; max-height: 470px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/9e20adf1996b43de84ab2f777ce5ee0e.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/9e20adf1996b43de84ab2f777ce5ee0e.jpg" width="613" height="470" alt="Python67-爬虫_第31张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <p>上图中的指纹是指request指纹,指纹能够唯一标识一个request,从而避免重复的reqeust请求</p> <p>所以redis中常存储待爬的request对象和已爬取的request的指纹</p> <p><strong>redis基础</strong></p> <p></p> <div class="image-package"> <div class="image-container" style="max-width: 594px; max-height: 224px;"> <div class="image-view"> <a href="http://img.e-com-net.com/image/info10/d876178d36524198b7e66f8b4b6e67d6.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info10/d876178d36524198b7e66f8b4b6e67d6.jpg" width="594" height="224" alt="Python67-爬虫_第32张图片" style="border:1px solid black;"></a> </div> </div> <div class="image-caption"> 在这里插入图片描述 </div> </div> <br> scrapy_redis的地址: https://github.com/rmax/scrapy-redis <p></p> </article> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1408112466889637888"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(Python67-爬虫)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1892456456029007872.htm" title="Python爬虫requests(详细)" target="_blank">Python爬虫requests(详细)</a> <span class="text-muted">dme.</span> <a class="tag" taget="_blank" href="/search/Python%E7%88%AC%E8%99%AB%E9%9B%B6%E5%9F%BA%E7%A1%80%E5%85%A5%E9%97%A8/1.htm">Python爬虫零基础入门</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>本文来学爬虫使用requests模块的常见操作。1.URL参数无论是在发送GET/POST请求时,网址URL都可能会携带参数,例如:http://www.5xclass.cn?age=19&name=dengres=requests.get(url="https://www.5xclass.cn?age=19&name=deng")res=requests.get(url="https://www</div> </li> <li><a href="/article/1892446997915430912.htm" title="Python中的 redis keyspace 通知_python 操作redis psubscribe(‘__keyspace@0__ ‘)" target="_blank">Python中的 redis keyspace 通知_python 操作redis psubscribe(‘__keyspace@0__ ‘)</a> <span class="text-muted">2301_82243733</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a> <div>最后Python崛起并且风靡,因为优点多、应用领域广、被大牛们认可。学习Python门槛很低,但它的晋级路线很多,通过它你能进入机器学习、数据挖掘、大数据,CS等更加高级的领域。Python可以做网络应用,可以做科学计算,数据分析,可以做网络爬虫,可以做机器学习、自然语言处理、可以写游戏、可以做桌面应用…Python可以做的很多,你需要学好基础,再选择明确的方向。这里给大家分享一份全套的Pytho</div> </li> <li><a href="/article/1892349116927766528.htm" title="Selenium使用指南" target="_blank">Selenium使用指南</a> <span class="text-muted">程序员杰哥</span> <a class="tag" taget="_blank" href="/search/selenium/1.htm">selenium</a><a class="tag" taget="_blank" href="/search/%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/1.htm">测试工具</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B/1.htm">测试用例</a><a class="tag" taget="_blank" href="/search/%E8%81%8C%E5%9C%BA%E5%92%8C%E5%8F%91%E5%B1%95/1.htm">职场和发展</a><a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E4%BA%BA%E7%94%9F/1.htm">程序人生</a><a class="tag" taget="_blank" href="/search/%E5%8A%9F%E8%83%BD%E6%B5%8B%E8%AF%95/1.htm">功能测试</a> <div>概述selenium是网页应用中最流行的自动化测试工具,可以用来做自动化测试或者浏览器爬虫等。官网地址为:相对于另外一款web自动化测试工具QTP来说有如下优点:免费开源轻量级,不同语言只需要一个体积很小的依赖包支持多种系统,包括Windows,Mac,Linux支持多种浏览器,包括Chrome,FireFox,IE,safari,opera等支持多语言,包括Java,C,python,c#等主流</div> </li> <li><a href="/article/1892348360938024960.htm" title="基于Python的搜索引擎的设计与实现" target="_blank">基于Python的搜索引擎的设计与实现</a> <span class="text-muted">AI大模型应用之禅</span> <a class="tag" taget="_blank" href="/search/DeepSeek/1.htm">DeepSeek</a><a class="tag" taget="_blank" href="/search/R1/1.htm">R1</a><a class="tag" taget="_blank" href="/search/%26amp%3B/1.htm">&</a><a class="tag" taget="_blank" href="/search/AI%E5%A4%A7%E6%A8%A1%E5%9E%8B%E4%B8%8E%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">AI大模型与大数据</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/kotlin/1.htm">kotlin</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a> <div>搜索引擎,Python,爬虫,自然语言处理,信息检索,索引,算法,数据库1.背景介绍在信息爆炸的时代,海量数据无处不在,高效地获取所需信息变得至关重要。搜索引擎作为信息获取的桥梁,扮演着不可或缺的角色。传统的搜索引擎往往依赖于庞大的服务器集群和复杂的算法,对资源消耗较大,且难以满足个性化搜索需求。基于Python的搜索引擎设计,则凭借Python语言的易学易用、丰富的第三方库和强大的社区支持,为开</div> </li> <li><a href="/article/1892340166937341952.htm" title="python进程数上限_python 多进程数量 对爬虫程序的影响" target="_blank">python进程数上限_python 多进程数量 对爬虫程序的影响</a> <span class="text-muted">weixin_39759995</span> <a class="tag" taget="_blank" href="/search/python%E8%BF%9B%E7%A8%8B%E6%95%B0%E4%B8%8A%E9%99%90/1.htm">python进程数上限</a> <div>1.首先看一下python多进程的优点和缺点多进程优点:1.稳定性好:多进程的优点是稳定性好,一个子进程崩溃了,不会影响主进程以及其余进程。基于这个特性,常常会用多进程来实现守护服务器的功能。然而多线程不足之处在于,任何一个线程崩溃都可能造成整个进程的崩溃,因为它们共享了进程的内存资源池。2.能充分利用多核cpu:由于python设计之初,没预料到多核cpu能够得到现在的发展,只考虑到了单核cpu</div> </li> <li><a href="/article/1892331846763606016.htm" title="python爬虫--安装XPath Helper" target="_blank">python爬虫--安装XPath Helper</a> <span class="text-muted">S903784597</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>给chrome浏览器安装xpath插件。-从网盘下载xpath的插件文件链接:https://pan.baidu.com/s/1B85d5cLDyAz1xUQqmL3uug?pwd=3306提取码:3306-在chrome中输入chrome://extensions/打开扩展程序。-将从百度网盘中下载的xpath.zip文件直接拖到浏览器的扩展程序页面中-得到chrome插件,将插件开关开启,并且</div> </li> <li><a href="/article/1892316219466379264.htm" title="使用Python爬虫实时监控行业新闻案例" target="_blank">使用Python爬虫实时监控行业新闻案例</a> <span class="text-muted">海拥✘</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>目录背景环境准备请求网页数据解析网页数据定时任务综合代码使用代理IP提升稳定性运行截图与完整代码总结在互联网时代,新闻的实时性和时效性变得尤为重要。很多行业、技术、商业等领域的新闻都可以为公司或者个人发展提供有价值的信息。如果你有一项需求是要实时监控某个行业的新闻,自动化抓取并定期输出这些新闻,Python爬虫可以帮你轻松实现这一目标。本文将通过一个案例,带你一步一步实现一个简单的Python爬虫</div> </li> <li><a href="/article/1892269295539384320.htm" title="Python爬虫-猫眼电影的影院数据" target="_blank">Python爬虫-猫眼电影的影院数据</a> <span class="text-muted">写python的鑫哥</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB%E6%A1%88%E4%BE%8B1000%E8%AE%B2/1.htm">爬虫案例1000讲</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E7%8C%AB%E7%9C%BC/1.htm">猫眼</a><a class="tag" taget="_blank" href="/search/%E7%94%B5%E5%BD%B1/1.htm">电影</a><a class="tag" taget="_blank" href="/search/%E7%94%B5%E5%BD%B1%E9%99%A2/1.htm">电影院</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE/1.htm">数据</a><a class="tag" taget="_blank" href="/search/%E9%87%87%E9%9B%86/1.htm">采集</a> <div>前言本文是该专栏的第46篇,后面会持续分享python爬虫干货知识,记得关注。本文笔者以猫眼电影为例子,获取猫眼的影院相关数据。废话不多说,具体实现思路和详细逻辑,笔者将在正文结合完整代码进行详细介绍。接下来,跟着笔者直接往下看正文详细内容。(附带完整代码)正文地址:aHR0cHM6Ly93d3cubWFveWFuLmNvbS8=目标:获取猫眼电影的影院数据1.项目场景介绍老规矩,我们还是通过接码</div> </li> <li><a href="/article/1892256428417150976.htm" title="Python从0到100(四):Python中的运算符介绍(补充)" target="_blank">Python从0到100(四):Python中的运算符介绍(补充)</a> <span class="text-muted">是Dream呀</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a> <div>前言:零基础学Python:Python从0到100最新最全教程。想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、计算机视觉、机器学习、神经网络以及人工智能相关知识,成为学习学习和学业的先行者!欢迎大家订阅专栏:零基础学Python:Python从0到100最新</div> </li> <li><a href="/article/1892256429172125696.htm" title="Python从0到100(三十五):beautifulsoup的学习" target="_blank">Python从0到100(三十五):beautifulsoup的学习</a> <span class="text-muted">是Dream呀</span> <a class="tag" taget="_blank" href="/search/Dream%E7%9A%84%E8%8C%B6%E8%AF%9D%E4%BC%9A/1.htm">Dream的茶话会</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/beautifulsoup/1.htm">beautifulsoup</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a> <div>前言:零基础学Python:Python从0到100最新最全教程。想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、计算机视觉、机器学习、神经网络以及人工智能相关知识,成为学习学习和学业的先行者!欢迎大家订阅专栏:零基础学Python:Python从0到100最新</div> </li> <li><a href="/article/1892196639985168384.htm" title="python分布式爬虫去重_Python分布式爬虫(三) - 爬虫基础知识" target="_blank">python分布式爬虫去重_Python分布式爬虫(三) - 爬虫基础知识</a> <span class="text-muted">weixin_39997311</span> <a class="tag" taget="_blank" href="/search/python%E5%88%86%E5%B8%83%E5%BC%8F%E7%88%AC%E8%99%AB%E5%8E%BB%E9%87%8D/1.htm">python分布式爬虫去重</a> <div>0相关源码1技术选型爬虫能做什么1.1scrapyVSrequests+beautifulsoup做爬虫的时候,经常都会听到scrapyVSrequests+beautifulsoup的组合在本次分布式爬虫实现中只用scrapy而不用后者的原因是:requests和beautifulsoup都是库,scrapy是一个框架框架中可以应用requests等,可以集合很多第三方库基于twisted(异步</div> </li> <li><a href="/article/1892195882443534336.htm" title="Scrapy分布式爬虫系统" target="_blank">Scrapy分布式爬虫系统</a> <span class="text-muted">ivwdcwso</span> <a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91/1.htm">开发</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a><a class="tag" taget="_blank" href="/search/scrapy/1.htm">scrapy</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E5%B8%83%E5%BC%8F/1.htm">分布式</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91/1.htm">开发</a> <div>一、概述在这篇博文中,我们将介绍如何使用Docker来部署Scrapy分布式爬虫系统,包括Scrapyd、Logparser和Scrapyweb三个核心组件。这种部署方式适用于Scrapy项目和Scrapy-Redis分布式爬虫项目。需要安装的组件:Scrapyd-服务端,用于运行打包后的爬虫代码,所有爬虫机器都需要安装。Logparser-服务端,用于解析爬虫日志,配合Scrapyweb进行实时</div> </li> <li><a href="/article/1892186799468507136.htm" title="使用Python抓取新闻媒体网站的最新头条与相关内容:深入的爬虫开发与数据分析实战" target="_blank">使用Python抓取新闻媒体网站的最新头条与相关内容:深入的爬虫开发与数据分析实战</a> <span class="text-muted">Python爬虫项目</span> <a class="tag" taget="_blank" href="/search/2025%E5%B9%B4%E7%88%AC%E8%99%AB%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/1.htm">2025年爬虫实战项目</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98/1.htm">数据挖掘</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>引言在互联网时代,新闻媒体网站是人们获取信息和了解世界的重要渠道。随着新闻的即时更新,获取最新头条并进行数据分析成为许多行业领域(如媒体、广告、舆情监测等)的重要需求。通过抓取新闻媒体网站的内容,我们不仅能获取各类新闻文章,还能为后续的数据分析、情感分析、舆情监控等提供基础数据。本篇博客将详细讲解如何使用Python编写一个爬虫,抓取新闻媒体网站的最新头条及其相关内容。我们将使用最新的技术栈,包括</div> </li> <li><a href="/article/1892125650370752512.htm" title="Python爬虫实战:获取笔趣阁图书信息,并做数据分析" target="_blank">Python爬虫实战:获取笔趣阁图书信息,并做数据分析</a> <span class="text-muted">ylfhpy</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a> <div>注意:以下内容仅供技术研究,请遵守目标网站的robots.txt规定,控制请求频率避免对目标服务器造成过大压力!1.环境准备与反爬策略pythonimportrequestsfrombs4importBeautifulSoupimportpandasaspdimportreimporttimeimportrandomfromfake_useragentimportUserAgent#需安装:pip</div> </li> <li><a href="/article/1892090313263083520.htm" title="如何利用Python爬虫获取淘宝分类详情:实战案例指南" target="_blank">如何利用Python爬虫获取淘宝分类详情:实战案例指南</a> <span class="text-muted">数据小爬虫@</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>在电商领域,淘宝作为中国最大的电商平台之一,其分类详情数据对于市场分析、竞争策略制定以及电商运营优化具有极高的价值。通过Python爬虫技术,我们可以高效地获取这些数据,为电商从业者提供强大的数据支持。本文将详细介绍如何利用Python编写爬虫程序,快速获取淘宝分类详情数据。一、准备工作(一)环境搭建确保你的开发环境中已经安装了以下必要的库:requests:用于发送HTTP请求。Beautifu</div> </li> <li><a href="/article/1892065588717613056.htm" title="Python 爬虫功能介绍" target="_blank">Python 爬虫功能介绍</a> <span class="text-muted">chengxuyuan1213_</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB/1.htm">网络爬虫</a> <div>在当今互联网信息爆炸的时代,数据的获取与分析成为了各行各业不可或缺的一部分。Python,作为一种简洁、易读且功能强大的编程语言,凭借其丰富的库和框架,在数据抓取(即网络爬虫)领域展现了极大的优势。本文旨在介绍Python爬虫的基础功能,帮助初学者快速入门,理解爬虫的基本工作原理及常用技术。一、什么是网络爬虫网络爬虫(WebCrawler),又称网络蜘蛛(WebSpider)或网络机器人(WebR</div> </li> <li><a href="/article/1892009610320080896.htm" title="Python爬虫+数据分析:京东商品评论数据接口" target="_blank">Python爬虫+数据分析:京东商品评论数据接口</a> <span class="text-muted">代码逐梦人</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB%E6%8A%80%E8%83%BD%E6%99%8B%E5%8D%87%E8%B7%AF%E7%BA%BF/1.htm">爬虫技能晋升路线</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a> <div>一、引言在电商领域,商品评论数据蕴含着丰富的信息,如消费者的满意度、产品的优缺点等。京东作为国内知名的电商平台,其商品评论数据对于商家进行市场调研、改进产品,以及消费者了解商品真实情况都具有重要价值。通过获取京东商品评论数据接口,我们可以方便、高效地获取这些有价值的信息,为后续的数据分析和决策提供支持。二、接口概述需要说明的是,京东并没有公开免费的商品评论数据接口供开发者随意使用。如果要获取京东商</div> </li> <li><a href="/article/1892009356183007232.htm" title="python爬虫多线程原理" target="_blank">python爬虫多线程原理</a> <span class="text-muted">代码逐梦人</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB%E6%8A%80%E8%83%BD%E6%99%8B%E5%8D%87%E8%B7%AF%E7%BA%BF/1.htm">爬虫技能晋升路线</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>多线程爬虫原理与优势在Python爬虫中,多线程是一种提升爬取效率的有效技术。在传统的单线程爬虫里,每次只能处理一个请求,只有等当前请求完成(包括发送请求、等待响应、解析数据)之后,才能开始下一个请求。而多线程爬虫可以让多个请求同时进行,在等待某个请求响应的时间里,CPU可以去处理其他请求,充分利用了CPU时间,大大提高了爬取效率。多线程爬虫的实现步骤1.引入必要的库importrequestsi</div> </li> <li><a href="/article/1892009356849901568.htm" title="Python爬虫+数据分析:淘宝商品评论页面数据" target="_blank">Python爬虫+数据分析:淘宝商品评论页面数据</a> <span class="text-muted">代码逐梦人</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB%E6%8A%80%E8%83%BD%E6%99%8B%E5%8D%87%E8%B7%AF%E7%BA%BF/1.htm">爬虫技能晋升路线</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a> <div>一、引言在电商平台中,商品评论包含了大量消费者的反馈信息,这些信息对于商家了解产品优缺点、改进服务,以及消费者做出购买决策都具有重要价值。淘宝作为国内知名的电商平台,其商品评论页面的数据蕴含着丰富的信息。通过Python爬虫技术获取这些数据,并运用数据分析方法进行处理和解读,可以挖掘出有价值的商业洞察。然而,需要注意的是,淘宝有严格的反爬机制,在进行爬虫操作时要遵守相关法律法规和平台规则,避免过度</div> </li> <li><a href="/article/1891974566327152640.htm" title="Python网络爬虫-WebSocket数据抓取" target="_blank">Python网络爬虫-WebSocket数据抓取</a> <span class="text-muted">程序小勇</span> <a class="tag" taget="_blank" href="/search/faiss/1.htm">faiss</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/1.htm">网络协议</a><a class="tag" taget="_blank" href="/search/websocket/1.htm">websocket</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>目录前言1、WebSocket请求的分析通常涉及以下几个方面:2、利用WebSocket爬取数据总结最后,创作不易!非常感谢大家的关注、点赞、评论啦!谢谢三连哦!好人好运连连,学习进步!工作顺利哦!博主介绍:✌专注于前后端、机器学习、人工智能应用领域开发的优质创作者、秉着互联网精神开源贡献精神,答疑解惑、坚持优质作品共享。本人是掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战,</div> </li> <li><a href="/article/1891930292613083136.htm" title="流行编程语言全解析:优势、应用与短板" target="_blank">流行编程语言全解析:优势、应用与短板</a> <span class="text-muted">a小胡哦</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a><a class="tag" taget="_blank" href="/search/c%E8%AF%AD%E8%A8%80/1.htm">c语言</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/swift/1.htm">swift</a><a class="tag" taget="_blank" href="/search/r%E8%AF%AD%E8%A8%80/1.htm">r语言</a> <div>Python:优势Python以其简洁、易读的语法闻名,新手能快速上手。丰富的库和框架,能极大地提高开发效率。适用领域数据科学与分析:处理和分析大规模数据集,进行数据可视化。典型示例:Google用Python进行数据分析,处理海量数据以支持各种业务决策。机器学习与人工智能:构建和训练模型。典型示例:OpenAI在很多人工智能项目中广泛使用Python,如GPT系列模型的研发。网络爬虫:轻松从网页</div> </li> <li><a href="/article/1891903033600700416.htm" title="052_爬虫_爬虫相关概念(引用《尚硅谷Python爬虫教程(小)小 白零基础速通》052章)" target="_blank">052_爬虫_爬虫相关概念(引用《尚硅谷Python爬虫教程(小)小 白零基础速通》052章)</a> <span class="text-muted">一个有趣的昵称</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>爬虫解释:通过程序,根据url(http://taobao.com)进行网页的爬取获取有用的信息实用程序模拟浏览器,去向服务发送请求,获取响应信息爬虫的核心爬取网页:爬取整个网页包含了网页中所的内容解析数据:将网页中得到的数据进行解析难点:爬虫和但爬虫之间的博弈爬虫的类型实例通用爬虫百度,360,Google,搜狗等搜索引擎功能访问网页-》抓取数据-》数据储存-》数据处理-》提供检索服务robot</div> </li> <li><a href="/article/1891899750693793792.htm" title="尚硅谷爬虫note007" target="_blank">尚硅谷爬虫note007</a> <span class="text-muted">CSDNy666999</span> <a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a> <div>一、urllib—异常1.urllib.error.HTTPError2.urllib.error.URLError#_*_coding:utf-8_*_#@Time:2025/2/1411:33#@Author:20250206-里奥#@File:demo26_异常#@Project:PythonProject10-14importurllib.requestimporturllib.error</div> </li> <li><a href="/article/1891820495158964224.htm" title="【Python爬虫(15)】从0到1:Python爬虫实战攻克电商网站动态数据堡垒" target="_blank">【Python爬虫(15)】从0到1:Python爬虫实战攻克电商网站动态数据堡垒</a> <span class="text-muted">奔跑吧邓邓子</span> <a class="tag" taget="_blank" href="/search/Python%E7%88%AC%E8%99%AB/1.htm">Python爬虫</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E7%94%B5%E5%95%86%E7%BD%91%E7%AB%99/1.htm">电商网站</a><a class="tag" taget="_blank" href="/search/%E5%8A%A8%E6%80%81%E6%95%B0%E6%8D%AE/1.htm">动态数据</a> <div>【Python爬虫】专栏简介:本专栏是Python爬虫领域的集大成之作,共100章节。从Python基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取,还涉及数据处理与分析。无论是新手小白还是进阶开发者,都能从中汲取知识,助力掌握爬虫核心技能,开拓技术视野。目录一、引言二、准备工作2.1环境搭建2.2目标电商网站分析三、攻克登</div> </li> <li><a href="/article/1891814682365325312.htm" title="字节跳动后端或大数据基础知识面试题及参考答案(2万字长文)" target="_blank">字节跳动后端或大数据基础知识面试题及参考答案(2万字长文)</a> <span class="text-muted">大模型大数据攻城狮</span> <a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">大数据</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E5%8E%82%E9%9D%A2%E8%AF%95/1.htm">大厂面试</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/leetcode/1.htm">leetcode</a> <div>目录Redis的数据类型Redis数据类型的底层数据结构三次握手、四次挥手Redis持久化机制购物车为什么用Redis存,是永久存储吗MySQL的InnoDB索引数据结构哪些SQL的关键字会让索引失效队列、栈、数组、链表有什么不同讲讲爬虫的构成爬虫抓到的数据不清洗吗?不去重吗?对爬虫的更多了解Linux进程间通信机制进程和线程的区别线程私有的数据讲一下堆排序,每次调整的时间复杂度?堆排序是稳定的吗</div> </li> <li><a href="/article/1891760265066770432.htm" title="爬虫快速上手之正则表达式总结" target="_blank">爬虫快速上手之正则表达式总结</a> <span class="text-muted">Athena945</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1.htm">正则表达式</a><a class="tag" taget="_blank" href="/search/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1.htm">正则表达式</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>目录一、正则表达式二、查找相关方法三、re.Match类的使用四、re.compile()方法的使用五、正则修饰符六、标点符号的特殊意义七、字母的特殊含义八、正则替换九、贪婪模式和非贪婪模式十、正则表达式小结一、正则表达式1、概念正则表达式是一个特殊的字符序列,通常被用来检索、替换那些符合某个模式(规则)的文本;在python中需要通过正则表达式对字符串进行匹配的时候,可以使用re模块实现全部的正</div> </li> <li><a href="/article/1891734789824770048.htm" title="Go分布式爬虫笔记(五)_golang分布式爬虫架构" target="_blank">Go分布式爬虫笔记(五)_golang分布式爬虫架构</a> <span class="text-muted">2401_87198107</span> <a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E5%B8%83%E5%BC%8F/1.htm">分布式</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a> <div>系统级别优化与架构设计:如何对服务进行拆分如何将服务链接在一起服务调用的关系以及调用频率各种问题:如何让服务随着负载的增加具有可扩展性?是否采用DDD的架构设计?如何进行分布式的协调?选择何种中间件、缓存数据库与存储数据库?使用何种通信方式?如何设计缓存与数据库的关系,才能避免缓存失效之后大量数据直接打到数据库导致的服务响应变慢甚至服务雪崩的问题呢?分布式系统中数据的一致性,如果业务能够接受读取到</div> </li> <li><a href="/article/1891722043909533696.htm" title="这知识点真细,Python获取HTTP响应头和响应体" target="_blank">这知识点真细,Python获取HTTP响应头和响应体</a> <span class="text-muted">梦想橡皮擦</span> <a class="tag" taget="_blank" href="/search/Python%E7%88%AC%E8%99%AB120/1.htm">Python爬虫120</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%B7%A5%E5%85%B7/1.htm">浏览器工具</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/python%E7%88%AC%E8%99%AB/1.htm">python爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%80%85%E5%B7%A5%E5%85%B7/1.htm">开发者工具</a> <div>哈喽!大家好,我是【梦想橡皮擦】,10年产研经验,致力于Python相关技术栈传播本文如果觉得不错,动动小手点个赞赞吧本文如果发现错误,欢迎在评论区中指正哦技术博客日更者,我喜欢写文章,如果任意一篇文章对你有帮助,就挺好的~欢迎大家订阅专栏⭐️⭐️《Python爬虫120》⭐️⭐️最近更新:2022年3月23日,橡皮擦的第610篇原创博客文章目录⛳️实战案例场景⛳️可获取的响应头⛳️实战案例场景这</div> </li> <li><a href="/article/1891707902046040064.htm" title="python aiohttp_Python-异步之aiohttp" target="_blank">python aiohttp_Python-异步之aiohttp</a> <span class="text-muted">weixin_39864101</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/aiohttp/1.htm">aiohttp</a> <div>什么是aiohttp?一个异步的HTTP客户端\服务端框架,基于asyncio的异步模块。可用于实现异步爬虫,更快于requests的同步爬虫。aiohttp和requestsrequests版爬虫requests同步方式连续30次简单爬取http://httpbin.org网站importrequestsfromdatetimeimportdatetimedeffetch(url):r=requ</div> </li> <li><a href="/article/1891582330024292352.htm" title="运用python制作一个完整的股票分析系统" target="_blank">运用python制作一个完整的股票分析系统</a> <span class="text-muted">大懒猫软件</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/django/1.htm">django</a><a class="tag" taget="_blank" href="/search/beautifulsoup/1.htm">beautifulsoup</a> <div>使用python制作一个股票分析系统,可以通过股票价格走势动态界面,实时动态监测不同类型股票的变化情况。以下是一个完整的股票分析系统开发指南,包括股票价格走势动态界面和实时监测功能。这个系统将结合网络爬虫、数据分析、机器学习和可视化技术,帮助你实时监测不同类型股票的变化情况。1.系统功能概述数据采集:使用网络爬虫技术从财经网站采集股票数据。数据处理:计算技术指标(如KDJ、BOLL)并进行数据预处</div> </li> <li><a href="/article/39.htm" title="java Illegal overloaded getter method with ambiguous type for propert的解决" target="_blank">java Illegal overloaded getter method with ambiguous type for propert的解决</a> <span class="text-muted">zwllxs</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/jdk/1.htm">jdk</a> <div>好久不来iteye,今天又来看看,哈哈,今天碰到在编码时,反射中会抛出 Illegal overloaded getter method with ambiguous type for propert这么个东东,从字面意思看,是反射在获取getter时迷惑了,然后回想起java在boolean值在生成getter时,分别有is和getter,也许我们的反射对象中就有is开头的方法迷惑了jdk,</div> </li> <li><a href="/article/166.htm" title="IT人应当知道的10个行业小内幕" target="_blank">IT人应当知道的10个行业小内幕</a> <span class="text-muted">beijingjava</span> <a class="tag" taget="_blank" href="/search/%E5%B7%A5%E4%BD%9C/1.htm">工作</a><a class="tag" taget="_blank" href="/search/%E4%BA%92%E8%81%94%E7%BD%91/1.htm">互联网</a> <div>10. 虽然IT业的薪酬比其他很多行业要好,但有公司因此视你为其“佣人”。   尽管IT人士的薪水没有互联网泡沫之前要好,但和其他行业人士比较,IT人的薪资还算好点。在接下的几十年中,科技在商业和社会发展中所占分量会一直增加,所以我们完全有理由相信,IT专业人才的需求量也不会减少。   然而,正因为IT人士的薪水普遍较高,所以有些公司认为给了你这么多钱,就把你看成是公司的“佣人”,拥有你的支配</div> </li> <li><a href="/article/293.htm" title="java 实现自定义链表" target="_blank">java 实现自定义链表</a> <span class="text-muted">CrazyMizzz</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a> <div>1.链表结构   链表是链式的结构 2.链表的组成    链表是由头节点,中间节点和尾节点组成    节点是由两个部分组成:       1.数据域       2.引用域 3.链表的实现 &nbs</div> </li> <li><a href="/article/420.htm" title="web项目发布到服务器后图片过一会儿消失" target="_blank">web项目发布到服务器后图片过一会儿消失</a> <span class="text-muted">麦田的设计者</span> <a class="tag" taget="_blank" href="/search/struts2/1.htm">struts2</a><a class="tag" taget="_blank" href="/search/%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87/1.htm">上传图片</a><a class="tag" taget="_blank" href="/search/%E6%B0%B8%E4%B9%85%E4%BF%9D%E5%AD%98/1.htm">永久保存</a> <div>  作为一名学习了android和j2ee的程序员,我们必须要意识到,客服端和服务器端的交互是很有必要的,比如你用eclipse写了一个web工程,并且发布到了服务器(tomcat)上,这时你在webapps目录下看到了你发布的web工程,你可以打开电脑的浏览器输入http://localhost:8080/工程/路径访问里面的资源。但是,有时你会突然的发现之前用struts2上传的图片</div> </li> <li><a href="/article/547.htm" title="CodeIgniter框架Cart类 name 不能设置中文的解决方法" target="_blank">CodeIgniter框架Cart类 name 不能设置中文的解决方法</a> <span class="text-muted">IT独行者</span> <a class="tag" taget="_blank" href="/search/CodeIgniter/1.htm">CodeIgniter</a><a class="tag" taget="_blank" href="/search/Cart/1.htm">Cart</a><a class="tag" taget="_blank" href="/search/%E6%A1%86%E6%9E%B6%E3%80%80/1.htm">框架 </a> <div>今天试用了一下CodeIgniter的Cart类时遇到了个小问题,发现当name的值为中文时,就写入不了session。在这里特别提醒一下。 在CI手册里也有说明,如下: $data = array( 'id' => 'sku_123ABC', 'qty' => 1, '</div> </li> <li><a href="/article/674.htm" title="linux回收站" target="_blank">linux回收站</a> <span class="text-muted">_wy_</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E5%9B%9E%E6%94%B6%E7%AB%99/1.htm">回收站</a> <div>今天一不小心在ubuntu下把一个文件移动到了回收站,我并不想删,手误了。我急忙到Nautilus下的回收站中准备恢复它,但是里面居然什么都没有。     后来我发现这是由于我删文件的地方不在HOME所在的分区,而是在另一个独立的Linux分区下,这是我专门用于开发的分区。而我删除的东东在分区根目录下的.Trash-1000/file目录下,相关的删除信息(删除时间和文件所在</div> </li> <li><a href="/article/801.htm" title="jquery回到页面顶端" target="_blank">jquery回到页面顶端</a> <span class="text-muted">知了ing</span> <a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a> <div>html代码: <h1 id="anchor">页面标题</h1> <div id="container">页面内容</div> <p><a href="#anchor" class="topLink">回到顶端</a><</div> </li> <li><a href="/article/928.htm" title="B树、B-树、B+树、B*树" target="_blank">B树、B-树、B+树、B*树</a> <span class="text-muted">矮蛋蛋</span> <a class="tag" taget="_blank" href="/search/B%E6%A0%91/1.htm">B树</a> <div>原文地址: http://www.cnblogs.com/oldhorse/archive/2009/11/16/1604009.html B树        即二叉搜索树:        1.所有非叶子结点至多拥有两个儿子(Left和Right); &nb</div> </li> <li><a href="/article/1055.htm" title="数据库连接池" target="_blank">数据库连接池</a> <span class="text-muted">alafqq</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0/1.htm">数据库连接池</a> <div>http://www.cnblogs.com/xdp-gacl/p/4002804.html @Anthor:孤傲苍狼 数据库连接池 用MySQLv5版本的数据库驱动没有问题,使用MySQLv6和Oracle的数据库驱动时候报如下错误: java.lang.ClassCastException: $Proxy0 cannot be cast to java.sql.Connec</div> </li> <li><a href="/article/1182.htm" title="java泛型" target="_blank">java泛型</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/java%E6%B3%9B%E5%9E%8B/1.htm">java泛型</a> <div>泛型 在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,任意化的缺点就是要实行强制转换,这种强制转换可能会带来不安全的隐患   泛型的特点:消除强制转换 确保类型安全 向后兼容   简单泛型的定义:      泛型:就是在类中将其模糊化,在创建对象的时候再具体定义 class fan</div> </li> <li><a href="/article/1309.htm" title="javascript闭包[两个小测试例子]" target="_blank">javascript闭包[两个小测试例子]</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a> <div>一.程序一 <script> var name = "The Window"; var Object_a = {   name : "My Object",   getNameFunc : function(){ var that = this;     return function(){     </div> </li> <li><a href="/article/1436.htm" title="探索JUnit4扩展:假设机制(Assumption)" target="_blank">探索JUnit4扩展:假设机制(Assumption)</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/Assumption/1.htm">Assumption</a><a class="tag" taget="_blank" href="/search/JUnit/1.htm">JUnit</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/1.htm">单元测试</a> <div>一.假设机制(Assumption)概述        理想情况下,写测试用例的开发人员可以明确的知道所有导致他们所写的测试用例不通过的地方,但是有的时候,这些导致测试用例不通过的地方并不是很容易的被发现,可能隐藏得很深,从而导致开发人员在写测试用例时很难预测到这些因素,而且往往这些因素并不是开发人员当初设计测试用例时真正目的,</div> </li> <li><a href="/article/1563.htm" title="【Gson四】范型POJO的反序列化" target="_blank">【Gson四】范型POJO的反序列化</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/POJO/1.htm">POJO</a> <div>在下面这个例子中,POJO(Data类)是一个范型类,在Tests中,指定范型类为PieceData,POJO初始化完成后,通过 String str = new Gson().toJson(data); 得到范型化的POJO序列化得到的JSON串,然后将这个JSON串反序列化为POJO   import com.google.gson.Gson; import java.</div> </li> <li><a href="/article/1690.htm" title="【Spark八十五】Spark Streaming分析结果落地到MySQL" target="_blank">【Spark八十五】Spark Streaming分析结果落地到MySQL</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/Stream/1.htm">Stream</a> <div>几点总结: 1. DStream.foreachRDD是一个Output Operation,类似于RDD的action,会触发Job的提交。DStream.foreachRDD是数据落地很常用的方法 2. 获取MySQL Connection的操作应该放在foreachRDD的参数(是一个RDD[T]=>Unit的函数类型),这样,当foreachRDD方法在每个Worker上执行时,</div> </li> <li><a href="/article/1817.htm" title="NGINX + LUA实现复杂的控制" target="_blank">NGINX + LUA实现复杂的控制</a> <span class="text-muted">ronin47</span> <a class="tag" taget="_blank" href="/search/nginx+lua/1.htm">nginx lua</a> <div>安装lua_nginx_module 模块 lua_nginx_module 可以一步步的安装,也可以直接用淘宝的OpenResty Centos和debian的安装就简单了。。 这里说下freebsd的安装: fetch http://www.lua.org/ftp/lua-5.1.4.tar.gz tar zxvf lua-5.1.4.tar.gz cd lua-5.1.4 ma</div> </li> <li><a href="/article/1944.htm" title="java-递归判断数组是否升序" target="_blank">java-递归判断数组是否升序</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div> public class IsAccendListRecursive { /*递归判断数组是否升序 * if a Integer array is ascending,return true * use recursion */ public static void main(String[] args){ IsAccendListRecursiv</div> </li> <li><a href="/article/2071.htm" title="Netty源码学习-DefaultChannelPipeline2" target="_blank">Netty源码学习-DefaultChannelPipeline2</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/netty/1.htm">netty</a> <div>Netty3的API http://docs.jboss.org/netty/3.2/api/org/jboss/netty/channel/ChannelPipeline.html 里面提到ChannelPipeline的一个“pitfall”: 如果ChannelPipeline只有一个handler(假设为handlerA)且希望用另一handler(假设为handlerB) 来</div> </li> <li><a href="/article/2198.htm" title="Java工具之JPS" target="_blank">Java工具之JPS</a> <span class="text-muted">chinrui</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>JPS使用     熟悉Linux的朋友们都知道,Linux下有一个常用的命令叫做ps(Process Status),是用来查看Linux环境下进程信息的。同样的,在Java Virtual Machine里面也提供了类似的工具供广大Java开发人员使用,它就是jps(Java Process Status),它可以用来</div> </li> <li><a href="/article/2325.htm" title="window.print分页打印" target="_blank">window.print分页打印</a> <span class="text-muted">ctrain</span> <a class="tag" taget="_blank" href="/search/window/1.htm">window</a> <div> function init() { var tt = document.getElementById("tt"); var childNodes = tt.childNodes[0].childNodes; var level = 0; for (var i = 0; i < childNodes.length; i++) { </div> </li> <li><a href="/article/2452.htm" title="安装hadoop时 执行jps命令Error occurred during initialization of VM" target="_blank">安装hadoop时 执行jps命令Error occurred during initialization of VM</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/jdk/1.htm">jdk</a><a class="tag" taget="_blank" href="/search/hadoop/1.htm">hadoop</a><a class="tag" taget="_blank" href="/search/jps/1.htm">jps</a> <div>在安装hadoop时,执行JPS出现下面错误   [slave16]root@192.168.11.10:/tmp/hsperfdata_hdfs# jps Error occurred during initialization of VM java.lang.Error: Properties init: Could not determine current working</div> </li> <li><a href="/article/2579.htm" title="PHP开发大型项目的一点经验" target="_blank">PHP开发大型项目的一点经验</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/%E9%87%8D%E6%9E%84/1.htm">重构</a> <div>一、变量 最好是把所有的变量存储在一个数组中,这样在程序的开发中可以带来很多的方便,特别是当程序很大的时候。变量的命名就当适合自己的习惯,不管是用拼音还是英语,至少应当有一定的意义,以便适合记忆。变量的命名尽量规范化,不要与PHP中的关键字相冲突。 二、函数 PHP自带了很多函数,这给我们程序的编写带来了很多的方便。当然,在大型程序中我们往往自己要定义许多个函数,几十</div> </li> <li><a href="/article/2706.htm" title="android笔记之--向网络发送GET/POST请求参数" target="_blank">android笔记之--向网络发送GET/POST请求参数</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>使用GET方法发送请求 private static boolean sendGETRequest (String path, Map<String, String> params) throws Exception{ //发送地http://192.168.100.91:8080/videoServi</div> </li> <li><a href="/article/2833.htm" title="linux复习笔记 之bash shell (3) 通配符" target="_blank">linux复习笔记 之bash shell (3) 通配符</a> <span class="text-muted">eksliang</span> <a class="tag" taget="_blank" href="/search/linux+%E9%80%9A%E9%85%8D%E7%AC%A6/1.htm">linux 通配符</a><a class="tag" taget="_blank" href="/search/linux%E9%80%9A%E9%85%8D%E7%AC%A6/1.htm">linux通配符</a> <div>转载请出自出处: http://eksliang.iteye.com/blog/2104387 在bash的操作环境中有一个非常有用的功能,那就是通配符。 下面列出一些常用的通配符,如下表所示 符号 意义 * 万用字符,代表0个到无穷个任意字符 ? 万用字符,代表一定有一个任意字符 [] 代表一定有一个在中括号内的字符。例如:[abcd]代表一定有一个字符,可能是a、b、c</div> </li> <li><a href="/article/2960.htm" title="Android关于短信加密" target="_blank">Android关于短信加密</a> <span class="text-muted">gqdy365</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>关于Android短信加密功能,我初步了解的如下(只在Android应用层试验):     1、因为Android有短信收发接口,可以调用接口完成短信收发;         发送过程:APP(基于短信应用修改)接受用户输入号码、内容——>APP对短信内容加密——>调用短信发送方法Sm</div> </li> <li><a href="/article/3087.htm" title="asp.net在网站根目录下创建文件夹" target="_blank">asp.net在网站根目录下创建文件夹</a> <span class="text-muted">hvt</span> <a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/hovertree/1.htm">hovertree</a><a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/Web+Forms/1.htm">Web Forms</a> <div>假设要在asp.net网站的根目录下建立文件夹hovertree,C#代码如下: string m_keleyiFolderName = Server.MapPath("/hovertree"); if (Directory.Exists(m_keleyiFolderName)) { //文件夹已经存在 return; } else { try { D</div> </li> <li><a href="/article/3214.htm" title="一个合格的程序员应该读过哪些书" target="_blank">一个合格的程序员应该读过哪些书</a> <span class="text-muted">justjavac</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a><a class="tag" taget="_blank" href="/search/%E4%B9%A6%E7%B1%8D/1.htm">书籍</a> <div>编者按:2008年8月4日,StackOverflow 网友 Bert F 发帖提问:哪本最具影响力的书,是每个程序员都应该读的? “如果能时光倒流,回到过去,作为一个开发人员,你可以告诉自己在职业生涯初期应该读一本, 你会选择哪本书呢?我希望这个书单列表内容丰富,可以涵盖很多东西。” 很多程序员响应,他们在推荐时也写下自己的评语。 以前就有国内网友介绍这个程序员书单,不过都是推荐数</div> </li> <li><a href="/article/3341.htm" title="单实例实践" target="_blank">单实例实践</a> <span class="text-muted">跑龙套_az</span> <a class="tag" taget="_blank" href="/search/%E5%8D%95%E4%BE%8B/1.htm">单例</a> <div>   1、内部类 public class Singleton { private static class SingletonHolder { public static Singleton singleton = new Singleton(); } public Singleton getRes</div> </li> <li><a href="/article/3468.htm" title="PO VO BEAN 理解" target="_blank">PO VO BEAN 理解</a> <span class="text-muted">q137681467</span> <a class="tag" taget="_blank" href="/search/VO/1.htm">VO</a><a class="tag" taget="_blank" href="/search/DTO/1.htm">DTO</a><a class="tag" taget="_blank" href="/search/po/1.htm">po</a> <div>PO:      全称是 persistant object持久对象 最形象的理解就是一个PO就是数据库中的一条记录。 好处是可以把一条记录作为一个对象处理,可以方便的转为其它对象。     BO:     全称是 business object:业务对象 主要作用是把业务逻辑封装为一个对象。这个对</div> </li> <li><a href="/article/3595.htm" title="战胜惰性,暗自努力" target="_blank">战胜惰性,暗自努力</a> <span class="text-muted">金笛子</span> <a class="tag" taget="_blank" href="/search/%E5%8A%AA%E5%8A%9B/1.htm">努力</a> <div>偶然看到一句很贴近生活的话:“别人都在你看不到的地方暗自努力,在你看得到的地方,他们也和你一样显得吊儿郎当,和你一样会抱怨,而只有你自己相信这些都是真的,最后也只有你一人继续不思进取。”很多句子总在不经意中就会戳中一部分人的软肋,我想我们每个人的周围总是有那么些表现得“吊儿郎当”的存在,是否你就真的相信他们如此不思进取,而开始放松了对自己的要求随波逐流呢? 我有个朋友是搞技术的,平时嘻嘻哈哈,以</div> </li> <li><a href="/article/3722.htm" title="NDK/JNI二维数组多维数组传递" target="_blank">NDK/JNI二维数组多维数组传递</a> <span class="text-muted">wenzongliang</span> <a class="tag" taget="_blank" href="/search/%E4%BA%8C%E7%BB%B4%E6%95%B0%E7%BB%84/1.htm">二维数组</a><a class="tag" taget="_blank" href="/search/jni/1.htm">jni</a><a class="tag" taget="_blank" href="/search/NDK/1.htm">NDK</a> <div>多维数组和对象数组一样处理,例如二维数组里的每个元素还是一个数组 用jArray表示,直到数组变为一维的,且里面元素为基本类型,去获得一维数组指针。给大家提供个例子。已经测试通过。 Java_cn_wzl_FiveChessView_checkWin( JNIEnv* env,jobject thiz,jobjectArray qizidata) { jint i,j; int s</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>