一、爬虫原理
1、http协议
超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。
2、http请求
[外链图片转存失败(img-4zvoifu2-1567686176832)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1565832939762.png)]
3、相应状态码
http状态返回代码 2xx (成功)
200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
201 (已创建) 请求成功并且服务器创建了新的资源。
202 (已接受) 服务器已接受请求,但尚未处理。
203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206 (部分内容) 服务器成功处理了部分 GET 请求。
http状态返回代码 3xx (重定向)
300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
http状态返回代码 4xx(请求错误)
400 (错误请求) 服务器不理解请求的语法。
401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 (禁止) 服务器拒绝请求。
404 (未找到) 服务器找不到请求的网页。
405 (方法禁用) 禁用请求中指定的方法。
406 (不接受) 无法使用请求的内容特性响应请求的网页。
407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
408 (请求超时) 服务器等候请求时发生超时。
409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求。
http状态返回代码 5xx(服务器错误)
500 (服务器内部错误) 服务器遇到错误,无法完成请求。
501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
4、Cookie 和 Session
cookie:的内容主要包括:名字,值,过期时间,路径和域。**路径与域一起构成 cookie
的作用范围。若不设置过期时间,则表示这个 cookie 的生命期为浏览器会话期间,关闭浏
览器窗口,cookie 就消失。这种生命期为浏览器会话期的 cookie 被称为会话 cookie。
会话 cookie 一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。
若设置了过期时间,浏览器就会把 cookie****保存到硬盘上,关闭后再次打开浏览器,这些 cookie
仍然有效直到超过设定的过期时间。
**2、cookie **和session的区别:
1)、cookie 数据存放在客户的浏览器上,session 数据放在服务器上。
2)、cookie 不是很安全,别人可以分析存放在本地的 COOKIE 并进行 COOKIE 欺骗, 考虑到安全应当使用 session。
3)、session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用 COOKIE。
4)、单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie。
请求头
http://www.useragentstring.com/pages/useragentstring.php?typ=Browser
二、requests模块
1、requestsm请求方法
requests.request():构造一个请求,支撑一下各方法的基础方法
requests.get():获取HTML网页的主要方法,对应HTTP的GET
requests.head():获取HTML网页头的信息方法,对应HTTP的HEAD
requests.post():向HTML网页提交POST请求方法,对应HTTP的POST
requests.put():向HTML网页提交PUT请求的方法,对应HTTP的RUT
requests.patch():向HTML网页提交局部修改请求,对应于HTTP的PATCH
requests.delete():向HTML页面提交删除请求,对应HTTP的DELETE
2、requests的13个参数
data:字典,字节序列或文件对象,作为Request的内容
data={'wd':'123'}
json:JSON格式的数据,作为Request的内容
headers:字典,HTTP定制头(模拟浏览器进行访问)
headers = {'user-agent': 'my-app/0.0.1'}
cokies:字典或CpplieJar,Request中的cookie
auth:元祖,支持HTTP认证功能
files:字典类型,传输文件
multiple_files = [
('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
timeout:设定超时时间,秒为单位
requests.get('http://github.com', timeout=0.001)
proxies:字典类型,设定访问代理服务器,可以增加登陆认证
proxies = {
"http": "http://10.10.1.10:3128",
"https": "http://10.10.1.10:1080",
}
allow_redirects:True//False,默认为True,重定向开关
stream:True/False,默认为True,获取内容立即下载开关
verify:True/False,默认为True,认证SSL证书开关
cert:本地SSL证书路径"""
requests.get('https://kennethreitz.org', cert=('/path/client.cert', '/path/client.key'))
3、requests的对象
s = requests.Session()
#初始化cookie
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
#发送请求
r = s.get("http://httpbin.org/cookies")
#打印
print(r.text)
1.请求与相应
#发送请求
r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
#获取请求头
r.headers
#获取连接状态
r.status_code
#获取cookies
r.cookies
#打印网页源代码
r.text
#设置编码格式
r.encoding
#获取网页编码
r.apparent_encoding
#下载
r.content
#JSON 响应内容
r.json
#自定义错误
r.raise_for_status()
#重定向
r.url
三、xpath的使用
1、xpath模块
模块的安装
pip install lxml
模块的导入
from lxml import etree
[外链图片转存失败(img-5XtEYEAg-1567686176834)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1561990509535.png)]
[外链图片转存失败(img-9LUX3qhr-1567686176835)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1561990533278.png)]
谓语
[外链图片转存失败(img-8i48DzAN-1567686176835)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1561990564431.png)]
2、xpath使用代码
html = etree.HTML(wb_data)
html_data = html.xpath('/html/body/div/ul/li/a')
打开HTML文件
html = etree.parse('test.html')
html_data = html.xpath('//*')<br>#打印是一个列表,需要遍历
print(html_data)
3、JSON模块
json 模块提供了四个功能:dumps、dump、loads、load,用于字符串 和 python 数据类
1.loads字符串转列表
a = '[1,2,3,4,5]'
print(json.loads(a))
print(type(json.loads(a)))
运行结果
[1, 1, 2, 3, 4, 5]
<class 'list'>
写入文件
a = {"name":"Tom", "age":23}
with open("test.json", "w", encoding='utf-8') as f:
# indent 超级好用,格式化保存字典,默认为None,小于0为零个空格
f.write(json.dumps(a, indent=4))
# json.dump(a,f,indent=4) # 和上面的效果一样
2、dumps元组转字符串
b = (1, 1, 2, 3, 4, 5)
print(type(json.dumps(b)))
结果:[1, 1, 2, 3, 4, 5]<class 'str'>
3、json.dump()–写到文件
def dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None,
default=None, sort_keys=False, **kw):
4、load写到内存
def load(fp, *, cls=None, object_hook=None, parse_float=None,
parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):
[外链图片转存失败(img-viTw2dub-1567686176836)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1562035871232.png)]
四、bs4css选择器Beautiful Soup
1、Beautiful Soup字符串转为lxml
from bs4 import BeautifulSoup
#可以是文件
soup = BeautifulSoup(open("index.html"))
#可以是字符串
soup = BeautifulSoup("<html>data</html>")
soup = BeautifulSoup(html_doc, 'lxml')
soup = BeautifulSoup(html_doc, 'html.parser')
2、模块的导入
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')
#几个简单的浏览结构化数据的方法
soup.title
获取
soup.title.name
soup.title.string
soup.title.parent.name
soup.p
soup.p['class']
soup.a
soup.find_all('a')
soup.find(id="link3")
3、对象的种类
1)Tag
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
type(tag)
# <class 'bs4.element.Tag'>
2)name
每个tag都有自己的名字,通过 .name
来获取:
tag.name = "blockquote"
tag
# <blockquote class="boldest">Extremely bold</blockquote>
如果改变了tag的name,那将影响所有通过当前Beautiful Soup对象生成的HTML文档:
tag.name = "blockquote"
tag
# <blockquote class="boldest">Extremely bold</blockquote>
3)Attributes
一个tag可能有很多个属性. tag <b class="boldest">
有一个 “class” 的属性,值为 “boldest” . tag的属性的操作方法与字典相同:
tag['class']
# u'boldest'
也可以直接”点”取属性, 比如: .attrs
:
tag.attrs
# {u'class': u'boldest'}
tag的属性可以被添加,删除或修改. 再说一次, tag的属性操作方法与字典一样
tag['class'] = 'verybold'
tag['id'] = 1
tag
# <blockquote class="verybold" id="1">Extremely bold</blockquote>
del tag['class']
del tag['id']
tag
# <blockquote>Extremely bold</blockquote>
tag['class']
# KeyError: 'class'
print(tag.get('class'))
# None
4 ) 多值属性
css_soup = BeautifulSoup('<p class="body strikeout"></p>')
css_soup.p['class']
# ["body", "strikeout"]
css_soup = BeautifulSoup('<p class="body"></p>')
css_soup.p['class']
# ["body"]
4、find_all详解
1)name参数
字符串
soup.find_all('b')
正则表达式
soup.find_all(re.compile("^b")
标签列表
soup.find_all(["a", "b"])
True可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点
soup.find_all(True)
参数可以是方法
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
soup.find_all(has_class_but_no_id)
# [<p class="title"><b>The Dormouse's story</b></p>,
# <p class="story">Once upon a time there were...</p>,
# <p class="story">...</p>]
find_all()
方法搜索当前tag的所有tag子节点
soup.find_all("title")
# [<title>The Dormouse's story</title>]
soup.find_all("p", "title")
# [<p class="title"><b>The Dormouse's story</b></p>]
soup.find_all("a")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
soup.find_all(id="link2")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
import re
soup.find(string=re.compile("sisters"))
# u'Once upon a time there were three little sisters; and their names were\n'
2)keyword参数
#按照id
soup.find_all(id='link2')
soup.find_all(href=re.compile("elsie"))
soup.find_all(id=True)
#多个参数
soup.find_all(href=re.compile("elsie"), id='link1')
#按CSS搜索
soup.find_all("a", class_="sister")
3)string参数
soup.find_all(string="Elsie")
# [u'Elsie']
soup.find_all(string=["Tillie", "Elsie", "Lacie"])
# [u'Elsie', u'Lacie', u'Tillie']
soup.find_all(string=re.compile("Dormouse"))
[u"The Dormouse's story", u"The Dormouse's story"]
def is_the_only_string_within_a_tag(s):
""Return True if this string is the only child of its parent tag.""
return (s == s.parent.string)
soup.find_all(string=is_the_only_string_within_a_tag)
# [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...']
4)limit
参数
soup.find_all("a", limit=2)
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
5)recursive
参数
会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数recursive=False
soup.html.find_all("title")
# [<title>The Dormouse's story</title>]
soup.html.find_all("title", recursive=False)
# []
5、其他的查找
1)find_parents() 和 find_parent()用来搜索当前节点的父辈节点
find_parents() 只查找一个
find_parent()查找所有的
a_string.find_parents("a")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
a_string.find_parent("p")
# <p class="story">Once upon a time there were three little sisters; and their names were
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
# and they lived at the bottom of a well.</p>
a_string.find_parents("p", class="title")
2)find_next_siblings() 和 find_next_sibling()
`find_next_siblings()` 方法返回所有符合条件的后面的兄弟节点, `find_next_sibling()`只返回符合条件的后面的第一个tag节点.
3)find_previous_siblings() 和 find_previous_sibling()
find_previous_siblings() 方法返回所有符合条件的前面的兄弟节点, find_previous_sibling() 方法返回第一个符合条件的前面的兄弟节点:
4)find_all_next() 和 find_next()
find_all_next() 方法返回所有符合条件的节点, find_next() 方法返回第一个符合条件的节点
5)find_all_previous() 和 find_previous()
find_all_previous( name , attrs , recursive , string , **kwargs )
find_previous( name , attrs , recursive , string , **kwargs )
find_all_previous() 方法返回所有符合条件的节点, find_previous() 方法返回第一个符合条件的节点.
6、子节点
1).contents 和 .children
.contents
属性可以将tag的子节点以列表的方式输出
.children
生成器,可以对tag的子节点进行循环:
2).descendants
.descendants
属性可以对所有tag的子孙节点进行递归循环
3).string
如果tag只有一个 NavigableString
类型子节点,那么这个tag可以使用 .string
得到子节点:
如果一个tag仅有一个子节点,那么这个tag也可以使用 .string
方法,输出结果与当前唯一子节点的 .string
结果相同:
head_tag.contents
# [<title>The Dormouse's story</title>]
head_tag.string
# u'The Dormouse's story'
4).strings 和 stripped_strings
如果tag中包含多个字符串 [2] ,可以使用 .strings
来循环获取:
.stripped_strings
可以去除多余空白内容:
5).parent
属性来获取某个元素的父节点
6).next_sibling 和 .previous_sibling
.next_sibling
和 .previous_sibling
属性来查询兄弟节点:
7).next_siblings 和 .previous_siblings
7、总结
.contents 和 .children都是循环子节点 | .contents以列表 .children` 生成器 |
---|---|
.descendants | 属性可以对所有tag的子孙节点进行递归循环 |
.string | tag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点 |
.strings 和 stripped_strings | .strings多个字符串 [2] .strings 来循环获取: .stripped_strings` 可以去除多余空白内容: |
.parent | 属性来获取某个元素的父节点 |
.next_sibling .previous_sibling | .next_sibling和 .previous_sibling` 属性来查询兄弟节点: |
.next_siblings 和 .previous_siblings |
五、Selenium模块
driver = webdriver.Firefox()
#初始化
driver.get(url)
#发送请求
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
#移动到页面底部
driver.execute_script("window.scrollTo(0, %d)" %(n))
#滑动
1、查找元素方法
driver.find_element_by_id(“passwd-id”) |
---|
find_element_by_tag_name |
driver.find_element_by_name(“passwd”) |
driver.find_element_by_xpath("//input[@id=‘passwd-id’]") |
find_element_by_link_text |
find_element_by_class_name |
find_element_by_css_selector |
在文本框输入数据
selement.send_keys()
通过”Keys”类来模式输入方向键
element.send_keys(" and some", Keys.ARROW_DOWN)
element.clear()
#清除文本框
2、填写表格
选择select
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_name('name'))
select.select_by_index(index)
select.select_by_visible_text("text")
select.select_by_value(value)
#获取所选项
options = select.options
提交
# Assume the button has the ID "submit" :)
driver.find_element_by_id("submit").click()
element.submit()
3、行为链
from selenium.webdriver import ActionChains
action = ActionChains(driver)
#拖放
action.drag_and_drop(element, target)
#移动光标
action.move_to_element()
#点击
action.click()
#输入
action.send_keys_to_element(对象,'内容')
action_chains.perform()
#输出页面源代码
print(driver.page_source)
窗口移动
driver.switch_to_window("windowName")
#迭代访问
for handle in driver.window_handles:
driver.switch_to_window(handle)
4、获取元素
#获取元素属性
logo.get_attribute('class')
#获取文本的值
input.text
#获取id
input.id
#获取location
input.location
#获取标签
input.tag_name
#获取大小
input.size
等待
#隐式等待
from selenium import webdriver
browser = webdriver.Chrome()
browser.implicitly_wait(10)
wait = WebDriverWait(browser, 10)
browser.get('https://www.zhihu.com/explore')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)
#显示等待
wait = WebDriverWait(browser, 10)
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
浏览器的前进和后退
back()#前进
forward()#后退
5、cookie操作
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies())
browser.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'zhaofan'})
print(browser.get_cookies())
browser.delete_all_cookies()
print(browser.get_cookies())
文件上传
定位<input type="file"> 元素并且调用 send_keys()
#方法传入要上传文件的路径,可以 是对于测试脚本的相对路径,也可以是绝对路径
6、取当前窗口的截图
driver.save_screenshot('screenshot.png')
7、执行JavaScript
browser.execute_script
8、PIL模块
im = Image.open("xiao.png")
#打开图片
1:1位像素,表示黑和白,但是存储的时候每个像素存储为8bit。
L:8位像素,表示黑和白。
P:8位像素,使用调色板映射到其他模式。
RGB:3x8位像素,为真彩色。
RGBA:4x8位像素,有透明通道的真彩色。
CMYK:4x8位像素,颜色分离。
YCbCr:3x8位像素,彩色视频格式。
I:32位整型像素。
F:32位浮点型像素。
PIL也支持一些特殊的模式,包括RGBX(有padding的真彩色)和RGBa(有自左乘alpha的真彩色)。
image.convert('L')
六、scrapy框架
1、安装模块
pip install scrapy
#依赖包
pip install pywin32
#lxml版本过高
pip uninstall lxml
pip install lxml==3.8
#解决 Scrapy 安装错误:Microsoft Visual C++ 14.0 is required..
http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted 下载 twisted 对应版本的 whl 文件
#创建项目
scrapy startproject tutorial
#运行蜘蛛
scrapy crawl mingyan2
2、配置文件
#提高并发性
CONCURRENT_REQUESTS = One hundred.
#增加扭曲的IO线程池的最大大小
REACTOR_THREADPOOL_MAXSIZE = 20.
降低log级别
LOG_LEVEL = 'INFO'
禁止cookies
COOKIES_ENABLED = False
禁止重试
RETRY_ENABLED = False
减小下载超时
DOWNLOAD_TIMEOUT = 15
禁止重定向
REDIRECT_ENABLED = False
启用 “Ajax Crawlable Pages” 爬取
AJAXCRAWL_ENABLED = True
3、Spider
name
#定义spider的名字
allowed_domains
#可选。包含了spider允许爬取的域名(domain)列表(list)。 当 OffsiteMiddleware 启用时, 域名不在列表中的URL不会被跟进。
start_urls
#URL列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取。
1、start_requests
()
该方法必须返回一个可迭代对象(iterable)。该对象包含了spider用于爬取的第一个Request。
def start_requests(self):
return [scrapy.FormRequest("http://www.example.com/login",
formdata={'user': 'john', 'pass': 'secret'},
callback=self.logged_in)]
2、make_requests_from_url`(url)
该方法接受一个URL并返回用于爬取的 Request
对象。 该方法在初始化request时被 start_requests()
调用,也被用于转化url为request。
3、parse`(response)
当response没有指定回调函数时,该方法是Scrapy处理下载的response的默认方法。
4、log(message**[, level, component]**)
使用 scrapy.log.msg()
方法记录(log)message。 log中自动带上该spider的 name
属性。
5、allowed_domains
可选。包含了spider允许爬取的域名(domain)列表(list)。 当 OffsiteMiddleware
启用时, 域名不在列表中的URL不会被跟进。
4、CrawlSpider
1、rules
一个包含一个(或多个) Rule
对象的集合(list)。 每个 Rule
对爬取网站的动作定义了特定表现。 Rule对象在下边会介绍。 如果多个rule匹配了相同的链接,则根据他们在本属性中被定义的顺序,第一个会被使用。
2、parse_start_url
当start_url的请求返回时,该方法被调用。 该方法分析最初的返回值并必须返回一个 Item
对象或者 一个 Request
对象或者 一个可迭代的包含二者对象。
3、link_extractor` 是一个 Link Extractor 对象。 其定义了如何从爬取到的页面提取链接。
callback
是一个callable或string(该spider中同名的函数将会被调用)。 从link_extractor中每获取到链接时将会调用该函数。该回调函数接受一个response作为其第一个参数, 并返回一个包含 Item
以及(或) Request
对象(或者这两者的子类)的列表(list)。
cb_kwargs
包含传递给回调函数的参数(keyword argument)的字典。
follow
是一个布尔(boolean)值,指定了根据该规则从response提取的链接是否需要跟进。 如果 callback
为None, follow
默认设置为 True
,否则默认为 False
。
process_links
是一个callable或string(该spider中同名的函数将会被调用)。 从link_extractor中获取到链接列表时将会调用该函数。该方法主要用来过滤。
process_request
是一个callable或string(该spider中同名的函数将会被调用)。 该规则提取到每个request时都会调用该函数。该函数必须返回一个request或者None。 (用来过滤request)
import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
class MySpider(CrawlSpider):
name = 'example.com'#爬虫命名
allowed_domains = ['example.com']#域名
start_urls = ['http://www.example.com']
rules = (
# 提取匹配 'category.php' (但不匹配 'subsection.php') 的链接并跟进链接(没有callback意味着follow默认为True)
Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))),
# 提取匹配 'item.php' 的链接并使用spider的parse_item方法进行分析
Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'),
)
def parse_item(self, response):
self.log('Hi, this is an item page! %s' % response.url)
item = scrapy.Item()
item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)')
item['name'] = response.xpath('//td[@id="item_name"]/text()').extract()
item['description'] = response.xpath('//td[@id="item_description"]/text()').extract()
return item
5、item pipeline
1)process_item`(self, item, spider)
#每个item pipeline组件都需要调用该方法,这个方法必须返回一个 Item (或任何继承类)对象, 或是抛出 DropItem 异常,被丢弃的item将不会被之后的pipeline组件所处理。
参数:
item (Item 对象) – 被爬取的item
spider (Spider 对象) – 爬取该item的spider
2)open_spider`(self, spider)
#当spider被开启时,这个方法被调用。
参数: spider (Spider 对象) – 被开启的spider
3)close_spider
(spider)
#当spider被关闭时,这个方法被调用
#参数: spider (Spider 对象) – 被关闭的spider
4)from_crawler
(cls, crawler)
#如果存在,则调用此类方法从爬虫程序创建管道实例。它必须返回管道的一个新实例。爬虫对象提供访问所有杂乱的核心组件,如设置和信号;这是管道访问它们并将其功能挂钩到Scrapy的一种方法。
5)Item pipeline 样例
from scrapy.exceptions import DropItem
class PricePipeline(object):
vat_factor = 1.15
def process_item(self, item, spider):
if item['price']:
if item['price_excludes_vat']:
item['price'] = item['price'] * self.vat_factor
return item
else:
raise DropItem("Missing price in %s" % item)
6)将item写入JSON文件
import json
class JsonWriterPipeline(object):
def __init__(self):
self.file = open('items.jl', 'wb')
def process_item(self, item, spider):
line = json.dumps(dict(item)) + "\n"
self.file.write(line)
return item
7、完整的案例
import pymongo
class MongoPipeline(object):
def __init__(self, mongo_uri, mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls, crawler):
return cls(
mongo_uri=crawler.settings.get('MONGO_URI'),
mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
collection_name = item.__class__.__name__
self.db[collection_name].insert(dict(item))
return item
8)去重
from scrapy.exceptions import DropItem
class DuplicatesPipeline(object):
def __init__(self):
self.ids_seen = set()
def process_item(self, item, spider):
if item['id'] in self.ids_seen:
raise DropItem("Duplicate item found: %s" % item)
else:
self.ids_seen.add(item['id'])
return item
9)启用一个Item Pipeline组件
ITEM_PIPELINES = {
'myproject.pipelines.PricePipeline': 300,
'myproject.pipelines.JsonWriterPipeline': 800,
}
6、启动指令
>>>redis-cli
>>>auth 123456
>>>lpush mypeople:start_url http://politics.people.com.cn/GB/1024/index1.html
附录:
短视频去水印网站
http://www.kaolajiexi.com/
音乐解析外链
https://link.hhtjim.com/
视频解析网站
腾讯视频,爱奇艺,优酷视频各大视频网站都可以解析……
https://jx.618g.com/?url= 视频解析
如果有跟好的解析网站可以私信
def process_item(self, item, spider):
collection_name = item.__class__.__name__
self.db[collection_name].insert(dict(item))
return item
8)去重
```python
from scrapy.exceptions import DropItem
class DuplicatesPipeline(object):
def __init__(self):
self.ids_seen = set()
def process_item(self, item, spider):
if item['id'] in self.ids_seen:
raise DropItem("Duplicate item found: %s" % item)
else:
self.ids_seen.add(item['id'])
return item
9)启用一个Item Pipeline组件
ITEM_PIPELINES = {
'myproject.pipelines.PricePipeline': 300,
'myproject.pipelines.JsonWriterPipeline': 800,
}
6、启动指令
>>>redis-cli
>>>auth 123456
>>>lpush mypeople:start_url http://politics.people.com.cn/GB/1024/index1.html
附录:
短视频去水印网站
http://www.kaolajiexi.com/
音乐解析外链
https://link.hhtjim.com/
视频解析网站
腾讯视频,爱奇艺,优酷视频各大视频网站都可以解析……
https://jx.618g.com/?url= 视频解析
如果有跟好的解析网站可以私信