当前位置: 首页 > article >正文

python爬虫总结,看这篇就够了

文章目录

  • 爬虫课程
    • urllib
        • urlopen函数
        • urlretrieve函数
        • urlencode函数和parse_qs函数
        • urlparse函数和urlsplit函数
        • request.Request函数
        • request.ProxyHandler函数
        • 关于编码和解码
        • 携带cookie登陆实例->人人网
        • 保存cookie到本地
        • 加载本地cookie
    • requests库
        • request添加代理
        • 绕过ssl证书
        • XPath使用
          • 使用实例
      • 电影天堂大型爬虫项目
          • enumerate函数使用
          • replace函数和strip函数
    • 正则表达式
        • 正则表达式匹配手机号
        • 正则表达式匹配邮箱
        • 正则表达式验证url
        • 正则表达式验证身份证
        • ^符号的含义
        • 贪婪模式和非贪婪模式
        • 匹配0-100的数字
        • 正则表达式中group的用法
        • 正则表达式中findall函数的用法
        • 正则表达式中sub函数的用法
        • 正则表达式中split函数的用法
        • 编译正则表达式-- re.compile
        • 匹配包括换行符内的所有字符re.DOTALL=re.S
    • json dump和dumps函数
        • json load函数和loads函数
    • csv文件读写操作
        • csv写入操作
    • python多线程操作
        • 传统代码
        • 多线程使用类
        • 多线程两个小的知识点
        • 多线程更改全局变量锁机制
        • Lock版本的生产者模式和消费者模式
        • Condition锁机制
        • 爬取表情包不开多线程
        • 多线程下载表情包
    • selenium和chromedriver驱动浏览器
        • selenium和chromedriver下载使用
        • selenium定位元素7种方式
        • selenium操作表单元素
        • select操作
        • selenium行为链
        • selenium操作cookies
        • selenium显示等待和隐式等待
        • selenium打开、切换多窗口
        • selenium设置代理
        • selenium webElement
    • 酷狗爬取Top500(列表生成器,去除列表中空元素)
      • scrapy 使用
        • 1、创建scrapy项目
  • Scrapy快速入门
    • 安装和文档:
    • 快速入门:
      • 创建项目:
      • 目录结构介绍:
      • 使用Scrapy框架爬取糗事百科段子:
        • 使用命令创建一个爬虫:
        • 爬虫代码解析:
        • 修改`settings.py`代码:
        • 完成的爬虫代码:
        • 运行scrapy项目:
        • scrapy自己总结笔记
        • JsonItemExporter和JsonLinesItemExporter
  • CrawlSpider
    • CrawlSpider爬虫:
      • 创建CrawlSpider爬虫:
      • LinkExtractors链接提取器:
      • Rule规则类:
      • 微信小程序社区CrawlSpider案例
      • scrapy shell
      • scrapy模拟登陆人人网
    • scrapy 下载文件和图片
        • 下载文件的 Files Pipeline
        • 下载图片的 Image Pipeline
      • map函数
      • User-Agent随机请求头
      • scrapy通过twisted实现异步存入数据库

爬虫课程

urllib

urlopen函数
from urllib import request
resp=request.urlopen('http://www.baidu.com')
print(resp.read())
read()读取所有数据
readline()只读取一行
readlines()逐行列表形势读取
urlretrieve函数
request.urlretrieve('http://www.xxx.com','index.html')

将网页中的内容保存到本地文件中

urlencode函数和parse_qs函数
from urllib import parse
params={'name':'xx','age':18,'greet':'hellow ddd'}
resp=parse.urlencode(params)
#将params编码
print(resp)
aa=parse.parse_qs(resp)
#将resp解码
print(aa)

搜索刘德华

from urllib import request
from urllib import parse
import ssl
#增加ssl证书验证,没有这句话报错
ssl._create_default_https_context = ssl._create_unverified_context
url='http://www.baidu.com/baidu'
params={'wd':'刘德华'}
#将汉字刘德华编码,得到整体url
qs=parse.urlencode(params)
print(qs)
url=url+'?'+qs
print(url)
resp=request.urlopen(url)
print(resp.read())
urlparse函数和urlsplit函数

url解析的两个函数

from urllib import parse
url='http://www.baidu.com/s?wd=python&uname=admin#1'
#两种获得参数的函数
result1=parse.urlparse(url)
result2=parse.urlsplit(url)
print(result1)
print(result2)#得到结果如下
ParseResult(scheme='http', netloc='www.baidu.com', path='/s', params='', query='wd=python&uname=admin', fragment='1')SplitResult(scheme='http', netloc='www.baidu.com', path='/s', query='wd=python&uname=admin', fragment='1')
request.Request函数
# encoding utf8
from urllib import request, parse
import sslssl._create_default_https_context = ssl._create_unverified_context
url = 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput='
#添加请求头部信息
headers = {'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) ''Chrome/83.0.4103.61 Safari/537.36 '
}
req = request.Request(url, headers=headers)
resp = request.urlopen(req)
print(resp.read().decode('utf-8'))
request.ProxyHandler函数
# encoding utf-8
from urllib import requesturl = 'http://httpbin.org/ip'
# resp=request.urlopen(url)
# print(resp.read())
#创建一个handler使用代理http或者https
handler = request.ProxyHandler({'http': '60.217.64.237:38829'})
opener = request.build_opener(handler)
resp = opener.open(url)
print(resp.read())
关于编码和解码
#write 必须写入一个str数据类型
#resp.read()读出来是一个bytes数据类型
#bytes-> decode -> str
#str-> encode -> bytes
携带cookie登陆实例->人人网

其中涉及到cookie的保存

# encoding utf-8
from urllib import request, parse
from http.cookiejar import CookieJarheaders = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:76.0) Gecko/20100101 Firefox/76.0'
}
data = {'email': '自己的手机号或者邮箱','password': '自己的密码'
}def get_opener():# 创建cookiejarcookiejar = CookieJar()# 创建handlerhandler = request.HTTPCookieProcessor(cookiejar)# 创建openeropener = request.build_opener(handler)return openerdef login_renren(opener):login_url = 'http://www.renren.com/PLogin.do'req = request.Request(login_url, headers=headers, data=parse.urlencode(data).encode('utf-8'))opener.open(req)#此处为大鹏的人人网地址
def visit_profile(opener):dapeng_url = 'http://www.renren.com/人人id/profile'resp = opener.open(dapeng_url)with open('renren.html', 'w', encoding='utf-8') as f:f.write(resp.read().decode('utf-8'))if __name__ == '__main__':opener = get_opener()login_renren(opener)visit_profile(opener)
保存cookie到本地
#encoding utf-8
from urllib import request
from http.cookiejar import MozillaCookieJar
cookiejar=MozillaCookieJar('cookie.txt')
handler=request.HTTPCookieProcessor(cookiejar)
opener=request.build_opener(handler)url='http://httpbin.org/cookies/set?course=abc'
resp=opener.open(url)
#其中的ignore_discard=True是为了让即将过期或者已经过期的cookie能够显示
cookiejar.save(ignore_discard=True)
加载本地cookie
#encoding utf-8
from urllib import request
from http.cookiejar import MozillaCookieJar
cookiejar=MozillaCookieJar('cookie.txt')
#在这里添加ignore_discard=True
cookiejar.load(ignore_discard=True)
handler=request.HTTPCookieProcessor(cookiejar)
opener=request.build_opener(handler)url='http://httpbin.org/cookies'
for cookie in cookiejar:print(cookie)

requests库

# endcoding utf-8
import requestsresp = requests.get('https://www.baidu.com/')
print(resp.content)
print(resp.url)
print(resp.status_code)
print(resp.encoding)
request添加代理
# encoding utf-8
import requestsproxy = {'http': '182.46.251.204:9999'
}
resp = requests.get('http://httpbin.org/ip', proxies=proxy)
print(resp.content)
绕过ssl证书
#添加verify=False绕过ssl证书验证
resp = requests.get('http://httpbin.org/ip', proxies=proxy,verify=False)
XPath使用
nodename             选取此节点的所有子节点
/                    从当前节点选取直接子节点
//                   从当前节点选取子孙节点
.                    选取当前节点
..                   选取当前节点的父节点
@                    选取属性
使用实例

获取所有的tr标签

# encoding utf-8
from lxml import etreeparser = etree.HTMLParser(encoding='utf-8')
html = etree.parse('test.html', parser=parser)
# 获取所有的tr标签
# xpath函数返回的为列表
trs = html.xpath('//tr')
for tr in trs:print(etree.tostring(tr, encoding='utf-8').decode('utf-8'))

获取第二个tr标签

tr = html.xpath('//tr[2]')
print(etree.tostring(tr, encoding='utf-8').decode('utf-8'))

获取所有类名为even的数据

trs=html.xpath('//tr[@class=even]')
print(etree.tostring(trs, encoding='utf-8').decode('utf-8'))

获取a标签的href属性

aList=html.xpath('//a/@href')
for a in aList:print(etree.tostring(a, encoding='utf-8').decode('utf-8'))
 #获取tr标签下所有a的href属性fullurl=tr.xpath('.//a/@href')#获取tr标签下的文字title=tr.xpath('./td[1]//text()')

电影天堂大型爬虫项目

# encoding utf-8
import requests
from lxml import etreeBASE_DOMAIN = 'https://www.dytt8.net'
HEADERS = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36','Referer': 'https://www.dytt8.net/html/gndy/dyzz/list_23_2.html'
}def get_detail_urls(url):resp = requests.get(url, headers=HEADERS)text = resp.texthtml = etree.HTML(text)detail_urls = html.xpath("//table[@class='tbspan']//a/@href")detail_urls = map(lambda url: BASE_DOMAIN + url, detail_urls)return detail_urlsdef parse_detail_page(url):movie = {}response = requests.get(url, headers=HEADERS)text = response.content.decode('gbk')html = etree.HTML(text)title = html.xpath("//font[@color='#07519a']/text()")[0]movie['title'] = titlezoomE = html.xpath("//div[@id='Zoom']")[0]cover = zoomE.xpath(".//img/@src")[0]movie['cover'] = coverdef parse_info(info, rule):return info.replace(rule, "").strip()infos = zoomE.xpath(".//text()")# 此处enumerate函数可以返回除了基本信息以外的索引号for index, info in enumerate(infos):# print(info)# print(index)# print("=" * 10)if info.startswith('◎年  代'):info = parse_info(info, "◎年  代")movie['year'] = infoelif info.startswith('◎产  地'):info = parse_info(info, "◎产  地")movie['country'] = infoelif info.startswith('◎类  别'):info = parse_info(info, "◎类  别")movie['category'] = infoelif info.startswith('◎上映日期'):info = parse_info(info, "◎上映日期")movie['show_time'] = infoelif info.startswith('◎豆瓣评分'):info = parse_info(info, "◎豆瓣评分")movie['douban_rating'] = infoelif info.startswith('◎片  长'):info = parse_info(info, "◎片  长")movie['duration'] = infoelif info.startswith('◎导  演'):info = parse_info(info, "◎导  演")movie['director'] = infoelif info.startswith('◎主  演'):info = parse_info(info, '◎主  演')actors = [info]# 此时在主演以下所有的演员列出来,写一个条件语句,将在为符号处切割来for x in range(index + 1, len(infos)):actor = infos[x].strip()if actor.startswith('◎'):breakactors.append(actor)elif info.startswith('◎简  介'):info = parse_info(info, '◎简  介')for x in range(index + 1, len(infos)):profile = infos[x].strip()if profile.startswith('【下载地址】'):breakmovie['profile'] = profiledownload_url = html.xpath("//td[@bgcolor='#fdfddf']//a/@href")[0]movie['download_url'] = download_urlreturn moviedef spider():base_url = 'https://www.dytt8.net/html/gndy/dyzz/list_23_{}.html'movies = []for x in range(1, 8):url = base_url.format(x)detail_urls = get_detail_urls(url)for detail_url in detail_urls:movie = parse_detail_page(detail_url)movies.append(movie)print(movies)if __name__ == '__main__':spider()
enumerate函数使用
#此处enumerate函数可以返回除了基本信息以外的索引号
for index, info in enumerate(infos):print(info)print(index)
replace函数和strip函数
def parse_info(info, rule):return info.replace(rule, "").strip()

上述代码中为将rule替换为空字符串,然后将字符串两侧的空格去除

正则表达式

\w	匹配字母数字及下划线
\W	匹配非字母数字及下划线
\s	匹配任意空白字符,等价于 [\t\n\r\f].
\S	匹配任意非空字符
\d	匹配任意数字,等价于 [0-9].
\D	匹配任意非数字
[...]	用来表示一组字符,单独列出:[amk] 匹配 'a''m''k'
[^...]	不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
# 点匹配任意字符
import re
text='hellow'
ret=re.match('.',text)
print(ret.group())
正则表达式匹配手机号
import re
#验证手机号码
text='15888888888'
#$符号代表末尾
ret=re.match('1[3578]\d{9}$',text)
print(ret.group())
正则表达式匹配邮箱
import re
#验证邮箱
text='sean_123@qq.com'
ret=re.match('\w+@[a-z]+\.[a-z]+',text)
print(ret.group())
正则表达式验证url
import re
text='https://www.runoob.com/python/python-reg-expressions.html'
ret=re.match('(http|https|ftp)://[^\s]+',text)
print(ret.group())
正则表达式验证身份证
import re
text='370982199909246666'
ret=re.match('\d{17}[\dxX]',text)
print(ret.group())
^符号的含义

在函数中^表示以。。。开始,在中括号中表示取反

贪婪模式和非贪婪模式
import re
#贪婪模式
text='<h1>标题</h1>'
ret=re.match('<.+>',text)
print(ret.group())#打印结果为:<h1>标题</h1>
import re
#非贪婪模式
text='<h1>标题</h1>'
#在匹配过程中最后添加?号
ret=re.match('<.+?>',text)
print(ret.group())#打印结果为:<h1>
匹配0-100的数字
import re
#匹配0-100之间的数字
text='100'
#其中第一位为1-9,第二位有或者没有,所以加'?',但是如果是多位的话还可以匹配,所以加$,两位数字以后结尾或者是结果为100时可以匹配
ret=re.match('[1-9]\d?$|100$',text)
print(ret.group())
正则表达式中group的用法
import re
text='The price of apples is $99 and the price of oranges is $10'
ret=re.match('.*(\$\d+).*(\$\d+)',text)
#打印正则表达式匹配的所有字符
print(ret.group())
#打印正则表达式中第一个圆括号中匹配的字符
print(ret.group(1))
#打印正则表达式中第二个圆括号中匹配的字符
print(ret.group(2))
#打印正则表达式中所有子分组中匹配的字符
print(ret.groups())
#打印正则表达式中第一个圆括号和第二个圆括号中匹配的字符
print(ret.group(1,2))
#运行结果
The price of apples is $99 and the price of oranges is $10
$99
$10
('$99', '$10')
('$99', '$10')
正则表达式中findall函数的用法

找出所有满足条件的,返回的为列表

import re
text='The price of apples is $99 and the price of oranges is $10'
ret=re.findall('\$\d+',text)
print(ret)
#打印结果为
['$99', '$10']
正则表达式中sub函数的用法
sub('正则表达式','你想替换成什么字符串','替换的文本','替换的个数')

将你匹配出的字符串替换成你想要的字符串

import re
text='The price of apples is $99 and the price of oranges is $10'
ret=re.sub('\$\d+',"0",text)
print(ret)
正则表达式中split函数的用法
import re
text='hellow wor adv'
ret=re.split(' ',text)
print(ret)
编译正则表达式-- re.compile

对于经常用到的正则表达式可以先用compile函数编译,后期直接调用,提高性能

import re
#添加了flag参数 re.VERBOSE后,可以在complie中添加注释
r = re.compile(r"""
\d+ #小数点前面
\.? #小数点本身
\d* #小数点后面
""",re.VERBOSE)
text = 'the number is 20.30'
ret = re.findall(r, text)
print(ret)
匹配包括换行符内的所有字符re.DOTALL=re.S

Python的正则表达式模块re,有一个re.DOTALL的参数。默认情况下,正则表达式中的dot(.),表示所有除了换行的字符,加上re.DOTALL参数后,就是真正的所有字符了,包括换行符(\n)

json dump和dumps函数

dumps输出为json格式的字符串

dump输出为json文本,与文件操作并行

# encoding utf-8
import json
data = {'username':'李华','sex':'male','age':16}
# in_json = json.dumps(data)
# print(in_json)
#ensure_ascii=False 这个鱼文件操作中encoding='utf-8'合并使用,可以解析中文
with open('abc.json','w',encoding='utf-8') as f:json.dump(data,f,ensure_ascii=False)
json load函数和loads函数

json.loads()解码python json格式
json.load()加载python json格式文件

import jsonjson_str = '{"username": "李华", "sex": "male", "age": 16}'# 将json格式的字符串转为python数据类型的对象
jsonData = json.loads(json_str)
print(jsonData)
print(type(jsonData))# 加载json文件
with open('abc.json', 'r',encoding='utf-8') as f:data = json.load(f)print(data)# 字典类型print(type(data))

csv文件读写操作

csv.reader()用法

#reader为一个迭代器,可以遍历,x为列表形式
reader=csv.reader(f)
#next函数可以遍历第一行,如此在for循环中从index=1开始
next(reader)
for x in reader:print(x)print(x[1])

csv.DictReader()用法:

reader=csv.DictReader(f)
for x in reader:print(x)print(x[1])
csv写入操作
# encoding utf-8
import csv#当文件为元组类型时,用demo1方法写入
def csv_write_demo1():headers = ['username', 'age', 'height']values = [('张三', '18', 175),('阿娇回家', '19', 175),('张以', '18', 175),]# newline为去除换行,如果没有newline参数,则回添加'\n'with open('csv_test.csv', 'w', encoding='utf-8', newline='') as f:writer = csv.writer(f)writer.writerow(headers)writer.writerows(values)#当文件为字典类型时。用demo2方法
def csv_write_demo2():headers = ['username', 'age', 'height']values = [{'username': '张三', 'age': 18, 'height': 190},{'username': '张d', 'age': 14, 'height': 190},{'username': '张dg', 'age': 18, 'height': 190},{'username': '张大概', 'age': 18, 'height': 190},]with open('111.csv','w',encoding='utf-8',newline='') as f:writer=csv.DictWriter(f,headers)#此处为写入头部信息,虽然上面传入了headers数据,但是需要以下代码写入writer.writeheader()writer.writerows(values)if __name__ == '__main__':csv_write_demo2()

python多线程操作

传统代码
import timedef coding():for x in range(3):print('正在写代码')time.sleep(1)def drawing():for x in range(3):print('正在画图中')time.sleep(1)
def main():coding()drawing()if __name__ == '__main__':main()#打印结果
#正在写代码
#正在写代码
#正在写代码
#正在画图中
#正在画图中
#正在画图中
#共耗时6s中

开启多线程使用threading,代码如下

#encoding utf-8import threading
import timedef coding():for x in range(3):print('正在写代码')time.sleep(1)def drawing():for x in range(3):print('正在画图中')time.sleep(1)
def main():tr1=threading.Thread(target=coding)tr2=threading.Thread(target=drawing)tr1.start()tr2.start()if __name__ == '__main__':main()
#打印结果如下
#正在写代码
#正在画图中
#正在写代码
#正在画图中
#正在画图中
#正在写代码
#共耗时3s

通过以上比较,多线程提高效率,一倍多

多线程使用类
#encoding utf-8import threading
import time
class CodingThread(threading.Thread):def run(self):for x in range(3):print('正在写代码')time.sleep(1)class DrawingThread(threading.Thread):def run(self):for x in range(3):print('正在画图中')time.sleep(1)def main():tr1 = CodingThread()tr2 = DrawingThread()tr1.start()tr2.start()if __name__ == '__main__':main()
多线程两个小的知识点
#当前线程的名称
threading.current_thread()
#查看当前线程总数
threading.enumerate()
多线程更改全局变量锁机制

变量锁只有在更改全局变量时启用,访问时无需添加线程机制锁

# encoding utf-8
import threadingVALUE = 0
#建立全局锁
gLock = threading.Lock()def add_value():global VALUE#开启锁gLock.acquire()for x in range(1000000):VALUE += 1#释放锁gLock.release()print(VALUE)def main():for x in range(2):tr = threading.Thread(target=add_value)tr.start()if __name__ == '__main__':main()
Lock版本的生产者模式和消费者模式

知识点

1、想要在函数中使用全局变量,需要添加global属性

2、Consumer(name=‘生产者线程%d’ % x)name为添加线程名称

# encoding utf-8import threading
import random
import timegMoney = 1000
gLock = threading.Lock()
gTotalTimes = 10
gTimes = 0class Producter(threading.Thread):def run(self):#想要在函数中使用全局变量,需要添加global属性global gMoneyglobal gTimeswhile True:money = random.randint(100, 1000)gLock.acquire()if gTimes >= 10:#如果在此处不添加释放锁,则会导致锁无法释放,卡死在这gLock.release()breakgMoney += moneygTimes += 1print('%s生产了%d元钱,剩余%d元钱' % (threading.current_thread(), money, gMoney))gLock.release()time.sleep(0.5)class Consumer(threading.Thread):def run(self):global gMoneywhile True:money = random.randint(100, 1000)gLock.acquire()if gMoney >= money:gMoney -= moneyprint('%s消费了%d元钱,剩余%d元钱' % (threading.current_thread(), money, gMoney))else:if gTimes >= gTotalTimes:gLock.release()breakprint('%s消费%d元钱,剩余%d元钱,不足!' % (threading.current_thread(), money, gMoney))gLock.release()time.sleep(0.5)def main():for x in range(3):#添加name属性,添加线程名称tr = Consumer(name='生产者线程%d' % x)tr.start()for x in range(5):tr = Producter(name='消费者线程%d' % x)tr.start()if __name__ == '__main__':main()
Condition锁机制
# encoding utf-8import threading
import random
import timegMoney = 1000
gCondition = threading.Condition()
gTotalTimes = 10
gTimes = 0class Producter(threading.Thread):def run(self):global gMoneyglobal gTimeswhile True:money = random.randint(100, 1000)gCondition.acquire()if gTimes >= 10:gCondition.release()breakgMoney += moneygTimes += 1print('%s生产了%d元钱,剩余%d元钱' % (threading.current_thread(), money, gMoney))gCondition.notify_all()gCondition.release()time.sleep(0.5)class Consumer(threading.Thread):def run(self):global gMoneywhile True:money = random.randint(100, 1000)gCondition.acquire()while gMoney < money:if gTimes >= gTotalTimes:gCondition.release()# 此处不可放break,如果放break的话只能退出当前if循环,但是如果是return的话,则会返回整个函数returnprint('%s消费%d元钱,剩余%d元钱,不足!' % (threading.current_thread(), money, gMoney))gCondition.wait()gMoney -= moneyprint('%s消费了%d元钱,剩余%d元钱' % (threading.current_thread(), money, gMoney))gCondition.release()time.sleep(0.5)def main():for x in range(3):tr = Consumer(name='生产者线程%d' % x)tr.start()for x in range(5):tr = Producter(name='消费者线程%d' % x)tr.start()if __name__ == '__main__':main()
爬取表情包不开多线程
# encoding utf-8
import requests
from lxml import etree
from urllib import request
import os
import redef parse_page(url):headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36'}resp = requests.get(url, headers=headers)text = resp.texthtml = etree.HTML(text)imgs = html.xpath("//div[@class='page-content text-center']//img[@class!='gif']")for img in imgs:img_url = img.get("data-original")# get可以获取其中的元素alt = img.get('alt')alt = re.sub(r'[!!。\.?\?]', '', alt)# 将文件名与后缀名分割开来,0为urlsuffix = os.path.splitext(img_url)[1]filename = alt + suffix# 将文件下载到本地request.urlretrieve(img_url, 'images/' + filename)def main():for x in range(1, 101):url = 'https://www.doutula.com/photo/list/?page=%d' % xparse_page(url)breakif __name__ == '__main__':main()

Queue线程安全队列

在线程中,访问一些全局变量,加锁是一个经常的过程。如果你是想把一些数据存储到某个队列中,那么 Python内置了一个线程安全的模块叫做 queue 模块。 Python中的queue模块中提供了同步的、线程安全以列类,包括FIFO(先进出)队列 Queue,LIFO(后入先出)队列 LifoQueue。这些队列都实现了锁原语(可以理解为原子操作,即么不做,更么都做完),能够在多程中直接使
用。可以使用队列来实现线程间的同步。相关的的数如下:

1.初始化 Queue( maxsize) 创建一个先进先出的队列。

  1. gsize():返回队列的大小。
  2. empty():判断队列是否为空。
  3. full():判断队列是否满了。
  4. get():从队列中取最后一个数据
  5. put():将一个数据放到队列中。

block参数如果为True,队列满了以后进入阻塞状态

多线程下载表情包
# encoding utf-8
import requests
from lxml import etree
from urllib import request
import os
import re
from queue import Queue
import threadingclass Producter(threading.Thread):headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36'}def __init__(self, page_queue, img_queue, *args, **kwargs):super(Producter, self).__init__(*args, **kwargs)self.page_queue = page_queueself.img_queue = img_queuedef run(self):while True:if self.page_queue.empty():breakurl = self.page_queue.get()self.parse_page(url)def parse_page(self, url):resp = requests.get(url, headers=self.headers)text = resp.texthtml = etree.HTML(text)imgs = html.xpath("//div[@class='page-content text-center']//img[@class!='gif']")for img in imgs:img_url = img.get("data-original")# get可以获取其中的元素alt = img.get('alt')alt = re.sub(r'[!!。\.?\?\*]', '', alt)# 将文件名与后缀名分割开来,0为urlsuffix = os.path.splitext(img_url)[1]filename = alt + suffixself.img_queue.put((img_url, filename))class Consumer(threading.Thread):def __init__(self, page_queue, img_queue, *args, **kwargs):super(Consumer, self).__init__(*args, **kwargs)self.page_queue = page_queueself.img_queue = img_queuedef run(self):while True:if self.img_queue.empty() and self.page_queue.empty():breakimg_url, filename = self.img_queue.get()# 将文件下载到本地request.urlretrieve(img_url, 'images/' + filename)print(filename + "  下载完成!")def main():page_queue = Queue(100)img_queue = Queue(1000)for x in range(1, 101):url = 'https://www.doutula.com/photo/list/?page=%d' % xpage_queue.put(url)for x in range(5):t = Producter(page_queue, img_queue)t.start()for x in range(5):t = Consumer(page_queue, img_queue)t.start()if __name__ == '__main__':main()

selenium和chromedriver驱动浏览器

selenium和chromedriver下载使用

下载地址:http://chromedriver.storage.googleapis.com/index.html

chromedriver测试

# encoding utf-8
from selenium import webdriverdriver_path = '/Users/xxx/Downloads/chromedriver'
#选择谷歌浏览器
driver = webdriver.Chrome(executable_path=driver_path)
#打开百度
driver.get('https:www.baidu.com')
#打印源代码
print(driver.page_source)
#关闭当前页面
driver.close()
#关闭整个页面
driver.quit()
selenium定位元素7种方式

1、find_element_by_id()

2、find_element_by_name()

3、find_element_by_class_name()

4、find_element_by_xpath()

5、find_element_by_css_selector()

6、find_element_by_tag_name()

7、find_element_by_link_text()

此种方法是专门用来定位文本链接的,比如百度首页右上角有“新闻”,“hao123”,“地图”等链接

# encoding utf-8
from selenium import webdriver
from lxml import etreedriver_path = '/Users/xxx/Downloads/chromedriver'
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https:www.baidu.com')
# 1、如果仅仅是解析网页,运用selenium+lxml方式最为快速
html = etree.HTML(driver.page_source)
# html.xpath("")
inputTag = driver.find_element_by_id('kw')
# 如果需要在输入框中赋值,需要使用send_keys
inputTag.send_keys('python')
selenium操作表单元素
# encoding utf-8
from selenium import webdriverdriver_path = '/Users/xxx/Downloads/chromedriver'
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https:www.baidu.com')inputTag = driver.find_element_by_id('kw')
# 如果需要在输入框中赋值,需要使用send_keys
inputTag.send_keys('python')
submitTag = driver.find_element_by_id('su')
# 清除输入框的内容
inputTag.clear()
# 点击百度一下按钮
submitTag.click()
select操作
from selenium import webdriver
from selenium.webdriver.support.select import Select
import timedriver_path = '/Users/xxx/Downloads/chromedriver'
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.sina.com.cn/')
#选择选择按钮
selectButton = Select(driver.find_element_by_id('slt_01'))
#通过索引点击
selectButton.select_by_index(1)
#通过地址进入
selectButton.select_by_value('地址')
#通过文字进入
selectButton.select_by_visible_text('新闻')time.sleep(4)
driver.close()
selenium行为链
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChainsdriver_path = '/xxx/xxx/chromedriver'
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com/')inputTag = driver.find_element_by_id('kw')
submitBtn = driver.find_element_by_id('su')
#创建行为链
actions = ActionChains(driver)
#将鼠标移动到input输入框中
actions.move_to_element(inputTag)
#将input输入框输入python
actions.send_keys_to_element(inputTag, 'python')
#将鼠标移动到submi按钮上
actions.move_to_element(submitBtn)
#点击按钮
actions.click(submitBtn)
#提交行为链
actions.perform()
selenium操作cookies
#cookies
from selenium import webdriverdriver_path = '/xxx/chromedriver'
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com/')#打印所有的cookie
for cookie in driver.get_cookies():print(cookie)print("=="*30)
#传递key,打印出key为PSTM的cookie信息
print(driver.get_cookie('PSTM'))
#删除key为PSTM的cookie
driver.delete_cookie('PSTM')
print(driver.get_cookie('PSTM'))
#删除所有的cookie
driver.delete_all_cookies()
selenium显示等待和隐式等待

1、selenium的显示等待
原理:显示等待,就是明确的要等到某个元素的出现或者是某个元素的可点击等条件,等不到,就一直等,除非在规定的时间之内都没找到,那么久跳出Exception

2、selenium的隐式等待
原理:隐式等待,就是在创建driver时,为浏览器对象创建一个等待时间,这个方法是得不到某个元素就等待一段时间,直到拿到某个元素位置。

# encoding utf-8
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ECdriver_path = '/xxx/chromedriver'
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('http://www.baidu.com')
# 隐式等待
# driver.implicity_wait(10)
# 显示等待
element = WebDriverWait(driver, 10).util(EC.presence_of_element_located((By.ID, 'kw'))
)
element.send_keys('hello')
driver.quit()
selenium打开、切换多窗口
# encoding utf-8
from selenium import webdriverdriver_path = '/xxx/chromedriver'
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('http://www.baidu.com')
# 打开新的标签页
driver.execute_script('window.open("https://www.douban.com")')
# driver切换到第二个标签页,window_handles代表句柄
driver.switch_to.window(driver.window_handles[1])
print(driver.current_url)
selenium设置代理
# encoding utf-8
from selenium import webdriverdriver_path = '/xxx/chromedriver'
# 设置代理
options = webdriver.ChromeOptions()
options.add_argument("--proxy-server=http://113.195.18.100:9999")
driver = webdriver.Chrome(executable_path=driver_path, options=options)
driver.get('http://www.baidu.com')
selenium webElement
# encoding utf-8
from selenium import webdriverdriver_path = '/xxx/chromedriver'
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https:www.baidu.com')submitBtn=driver.find_element_by_id('su')
#driver继承自webelement,这个标签的某个属性
print(submitBtn.get_attribute("value"))
#保存截图
driver.save_screenshot('baidu.png')

酷狗爬取Top500(列表生成器,去除列表中空元素)

# encoding utf-8
import requests
from lxml import etree
from lxml.html import fromstring, tostringdef request_top_url():url = 'https://www.kugou.com/yy/rank/home/1-8888.html?from=rank'headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:77.0) Gecko/20100101 Firefox/77.0'}resp = requests.get(url, headers=headers)text = resp.textparse_detail_page(text)def parse_detail_page(text):html = etree.HTML(text)ranks = html.xpath("//span[@class='pc_temp_num']//text()")titles = html.xpath("//div[@class='pc_temp_songlist ']/ul/li")times = html.xpath("//span[@class='pc_temp_time']/text()")links=html.xpath("//a[@class='pc_temp_songname']/@href")titles1=[]for title in titles:title=title.get('title')titles1.append(title)# print(titles1)#列表生成器ranks = [r.strip() for r in ranks if len(r.strip())]times = [r.strip() for r in times]# for title in titles:#     print(title)# print(titles)#解压缩for rank, title, time,link in zip(ranks, titles1, times,links):song={'rank':rank,'title':title,'time':time,'link':link}print(song)# print()def main():request_top_url()if __name__ == '__main__':main()

scrapy 使用

1、创建scrapy项目

1、创建项目

scrapy startproject [项目名称]

2、创建爬虫

scrapy genspider [爬虫名字] [爬虫域名]

注意爬虫名字跟项目名称不能冲突

spiders:存放你Spider文件,也就是你爬取的py文件

items.py:相当于一个容器,储存爬取下来的数据类型。和字典较像

middlewares.py:定义Downloader Middlewares(下载器中间件)和Spider Middlewares(蜘蛛中间件)的实现

pipelines.py:定义Item Pipeline的实现,实现数据的清洗,储存,验证。

settings.py:全局配置(请求头、多久发送一次请求、代理池)

scrapy.cfg:配置文件

Scrapy快速入门

安装和文档:

  1. 安装:通过pip install scrapy即可安装。
  2. Scrapy官方文档:http://doc.scrapy.org/en/latest
  3. Scrapy中文文档:http://scrapy-chs.readthedocs.io/zh_CN/latest/index.html

注意:

  1. ubuntu上安装scrapy之前,需要先安装以下依赖:
    sudo apt-get install python3-dev build-essential python3-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev,然后再通过pip install scrapy安装。
  2. 如果在windows系统下,提示这个错误ModuleNotFoundError: No module named 'win32api',那么使用以下命令可以解决:pip install pypiwin32

快速入门:

创建项目:

要使用Scrapy框架创建项目,需要通过命令来创建。首先进入到你想把这个项目存放的目录。然后使用以下命令创建:

scrapy startproject [项目名称]

目录结构介绍:

以下介绍下主要文件的作用:

  1. items.py:用来存放爬虫爬取下来数据的模型。
  2. middlewares.py:用来存放各种中间件的文件。
  3. pipelines.py:用来将items的模型存储到本地磁盘中。
  4. settings.py:本爬虫的一些配置信息(比如请求头、多久发送一次请求、ip代理池等)。
  5. scrapy.cfg:项目的配置文件。
  6. spiders包:以后所有的爬虫,都是存放到这个里面。

使用Scrapy框架爬取糗事百科段子:

使用命令创建一个爬虫:
scrapy gensipder qsbk "qiushibaike.com"

创建了一个名字叫做qsbk的爬虫,并且能爬取的网页只会限制在qiushibaike.com这个域名下。

爬虫代码解析:
import scrapyclass QsbkSpider(scrapy.Spider):name = 'qsbk'allowed_domains = ['qiushibaike.com']start_urls = ['http://qiushibaike.com/']def parse(self, response):pass

其实这些代码我们完全可以自己手动去写,而不用命令。只不过是不用命令,自己写这些代码比较麻烦。
要创建一个Spider,那么必须自定义一个类,继承自scrapy.Spider,然后在这个类中定义三个属性和一个方法。

  1. name:这个爬虫的名字,名字必须是唯一的。
  2. allow_domains:允许的域名。爬虫只会爬取这个域名下的网页,其他不是这个域名下的网页会被自动忽略。
  3. start_urls:爬虫从这个变量中的url开始。
  4. parse:引擎会把下载器下载回来的数据扔给爬虫解析,爬虫再把数据传给这个parse方法。这个是个固定的写法。这个方法的作用有两个,第一个是提取想要的数据。第二个是生成下一个请求的url。
修改settings.py代码:

在做一个爬虫之前,一定要记得修改setttings.py中的设置。两个地方是强烈建议设置的。

  1. ROBOTSTXT_OBEY设置为False。默认是True。即遵守机器协议,那么在爬虫的时候,scrapy首先去找robots.txt文件,如果没有找到。则直接停止爬取。
  2. DEFAULT_REQUEST_HEADERS添加User-Agent。这个也是告诉服务器,我这个请求是一个正常的请求,不是一个爬虫。
完成的爬虫代码:
  1. 爬虫部分代码:

     import scrapyfrom abcspider.items import QsbkItemclass QsbkSpider(scrapy.Spider):name = 'qsbk'allowed_domains = ['qiushibaike.com']start_urls = ['https://www.qiushibaike.com/text/']def parse(self, response):outerbox = response.xpath("//div[@id='content-left']/div")items = []for box in outerbox:author = box.xpath(".//div[contains(@class,'author')]//h2/text()").extract_first().strip()content = box.xpath(".//div[@class='content']/span/text()").extract_first().strip()item = QsbkItem()item["author"] = authoritem["content"] = contentitems.append(item)return items
  2. items.py部分代码:

     import scrapyclass QsbkItem(scrapy.Item):author = scrapy.Field()content = scrapy.Field()
  3. pipeline部分代码:

     import jsonclass AbcspiderPipeline(object):def __init__(self):self.items = []def process_item(self, item, spider):self.items.append(dict(item))print("="*40)return itemdef close_spider(self,spider):with open('qsbk.json','w',encoding='utf-8') as fp:json.dump(self.items,fp,ensure_ascii=False)
运行scrapy项目:

运行scrapy项目。需要在终端,进入项目所在的路径,然后scrapy crawl [爬虫名字]即可运行指定的爬虫。如果不想每次都在命令行中运行,那么可以把这个命令写在一个文件中。以后就在pycharm中执行运行这个文件就可以了。比如现在新创建一个文件叫做start.py,然后在这个文件中填入以下代码:

from scrapy import cmdlinecmdline.execute("scrapy crawl qsbk".split())
scrapy自己总结笔记

1、response是一个scrapy.http.response.html.HtmlResponse对象,可执行xpath语法和css语法来执行查询。

2、提取出来的数据是一个Selector或者是一个SelectorList对象,如果想要获取字符串,应该执行get()或者getall()方法。

3、getall()方法获取Selector中所有的文本,返回的是一个列表。

4、get()方法获取Selector中第一个文本,返回的是一个str类型。

5、如果数据解析回来,要传给pipline处理,那么可以用yield来返回。或者是收集所有的item。最后统一return返回。

6、item:建议在items.py中定义好魔性,以后就不用再使用自店。

7、pipline:这个是专门用来保存数据的。其中三个方法是会经常用的

  • open_spider(self, spider) :当爬虫打开的时候执行

  • process_item(self, item, spider):当爬虫有item传过来的时候会被调用。

  • close_spider(self, spider):当爬虫关闭的时候会被调用。

    要激活pipline,应该在setting.py中,设置ITEM_PIPELINES。示例如下:

    ITEM_PIPELINES = {'qsbk.pipelines.QsbkPipeline': 300,
    }
JsonItemExporter和JsonLinesItemExporter

保存json数据的时候可以使用这两个类让操作变得更简单

1、JsonItemExporter:这个是每次把数据添加到内存中,最后统一写入磁盘中。好处是存储的数据是一个满足json规则的数据,坏处是如果数据量比较大,会比较耗内存,示例代码如下

from scrapy.exporters import JsonItemExporterclass QsbkPipeline:def __init__(self):self.f = open('duanzi.json', 'wb')self.exporter = JsonItemExporter(self.f, ensure_ascii=False, encoding='utf-8')self.exporter.start_exporting()def open_spider(self, spider):print('爬虫开始。。')def process_item(self, item, spider):self.exporter.export_item(item)return itemdef close_spider(self, spider):self.exporter.finish_exporting()self.f.close()print('爬虫结束了。。。')

2、JsonLinesItemExporter:这个是每次调用export_item的时候就把这个item存储到硬盘中。坏处是每一个字典一行,整个文件不是一个满足json格式的文件。好处是每次处理数据的时候就直接存储到了硬盘中,这样不会耗内存,数据也比较安全。示例代码如下

from scrapy.exporters import JsonLinesItemExporterclass QsbkPipeline:def __init__(self):self.f = open('duanzi.json', 'wb')self.exporter = JsonLinesItemExporter(self.f, ensure_ascii=False, encoding='utf-8')def open_spider(self, spider):print('爬虫开始。。')def process_item(self, item, spider):self.exporter.export_item(item)return itemdef close_spider(self, spider):self.f.close()print('爬虫结束了。。。')

CrawlSpider

在上一个糗事百科的爬虫案例中。我们是自己在解析完整个页面后获取下一页的url,然后重新发送一个请求。有时候我们想要这样做,只要满足某个条件的url,都给我进行爬取。那么这时候我们就可以通过CrawlSpider来帮我们完成了。CrawlSpider继承自Spider,只不过是在之前的基础之上增加了新的功能,可以定义爬取的url的规则,以后scrapy碰到满足条件的url都进行爬取,而不用手动的yield Request

CrawlSpider爬虫:

创建CrawlSpider爬虫:

之前创建爬虫的方式是通过scrapy genspider [爬虫名字] [域名]的方式创建的。如果想要创建CrawlSpider爬虫,那么应该通过以下命令创建:

scrapy genspider -t crawl [爬虫名字] [域名]

LinkExtractors链接提取器:

使用LinkExtractors可以不用程序员自己提取想要的url,然后发送请求。这些工作都可以交给LinkExtractors,他会在所有爬的页面中找到满足规则的url,实现自动的爬取。以下对LinkExtractors类做一个简单的介绍:

class scrapy.linkextractors.LinkExtractor(allow = (),deny = (),allow_domains = (),deny_domains = (),deny_extensions = None,restrict_xpaths = (),tags = ('a','area'),attrs = ('href'),canonicalize = True,unique = True,process_value = None
)

主要参数讲解:

  • allow:允许的url。所有满足这个正则表达式的url都会被提取。
  • deny:禁止的url。所有满足这个正则表达式的url都不会被提取。
  • allow_domains:允许的域名。只有在这个里面指定的域名的url才会被提取。
  • deny_domains:禁止的域名。所有在这个里面指定的域名的url都不会被提取。
  • restrict_xpaths:严格的xpath。和allow共同过滤链接。

Rule规则类:

定义爬虫的规则类。以下对这个类做一个简单的介绍:

class scrapy.spiders.Rule(link_extractor, callback = None, cb_kwargs = None, follow = None, process_links = None, process_request = None
)

主要参数讲解:

  • link_extractor:一个LinkExtractor对象,用于定义爬取规则。
  • callback:满足这个规则的url,应该要执行哪个回调函数。因为CrawlSpider使用了parse作为回调函数,因此不要覆盖parse作为回调函数自己的回调函数。
  • follow:指定根据该规则从response中提取的链接是否需要跟进。
  • process_links:从link_extractor中获取到链接后会传递给这个函数,用来过滤不需要爬取的链接。

微信小程序社区CrawlSpider案例

主程序代码如下

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ..items import WxappItemclass WxappApiderSpider(CrawlSpider):name = 'wxapp_apider'allowed_domains = ['wxapp-union.com']start_urls = ['http://www.wxapp-union.com/portal.php?mod=list&catid=2&page=1']rules = (Rule(LinkExtractor(allow=r'.+mod=list&catid=2&page=\d'),  follow=True),Rule(LinkExtractor(allow=r'.+article-.+\.html'), callback='parse_item', follow=True),)def parse_item(self, response):title=response.xpath("//h1[@class='ph']/text()").get()authors_p=response.xpath("//p[@class='authors']")author=authors_p.xpath(".//a/text()").get()pub_time=authors_p.xpath(".//span/text()").get()content=response.xpath("//td[@id='article_content']//text()").getall()content="".join(content)item=WxappItem(title=title,author=author,pub_time=pub_time,content=content)yield item

1、其中LinkExtractor中的allow中填写允许的域名,其中填写正则表达式,满足正则表达式的都会被提取。

2、什么情况下使用follow,如果在爬取页面的时候,需要将满足条件的url再进行跟进,设置为True,否则设置为False。

3、什么情况下使用callback:如果这个url对应的页面,只是为了获取更多的url,并不需要里面具体的数据,那么可以不指定callback。

scrapy shell

1、可以方便的做一些数据提取的测试代码。

2、如果想要执行scrapy命令,要先进入到scrapy所在的环境中。

3、如果想要夺取某个项目的配置信息,那么应该先禁图到这个项目中,再执行scrapy shell命令。

scrapy shell 'url地址'

scrapy模拟登陆人人网

1、想要发送post请求,那么推荐使用scrapy FormRequest0方法,可以方便的指定表单数据。

2、如果想在爬虫一开始的时候就发送post请求,吗么应该重写start_requests方法,在这个方法中发送post请求,代码如下:

import scrapyclass RenrenSpider(scrapy.Spider):name = 'renren'allowed_domains = ['renren.com']start_urls = ['http://renren.com/']
#此处为重写start_requests方法,发送post请求登陆def start_requests(self):url='http://www.renren.com/PLogin.do'data = {'email': '手机号','password': '密码'}request=scrapy.FormRequest(url=url,formdata=data,callback=self.parse_page)yield requestdef parse_page(self,response):request=scrapy.Request(url='http://www.renren.com/id/profile',callback=self.parse_profile)yield requestdef parse_profile(self,response):with open('dapeng.html','w',encoding='utf-8') as  f:f.write(response.text)

scrapy 下载文件和图片

下载文件的 Files Pipeline

当使用Files Pipeline 下载文件的时候,按照以下步骤来完成:

  1. 定义好一个Items ,然后在这个 item 中定义两个属性,分别为 file_urls 以及 filesfile_urls是用来存储需要下载的图片的url链接,需要给一个列表。
  2. 当文件下载完成后,会把文件下载的相关信息存储到itemfiles属性中。比如下载路径、下载的url和文件的校验码等。
  3. 在配置文件 settings.py中配置 FILES_STORE,这个配置是用来设置文件下载下来的路径。
  4. 启动 pipeline:在 ITEM_PIPELINES中设置 scrapy.pipelines.files.FilesPipeline:1
下载图片的 Image Pipeline

当使用Image Pipeline下载文件的时候,按照以下步骤来完成:

  1. 定义好一个Item,然后在这个 Item 中定义两个属性,分别为 image_urls以及 imagesimage_urls是用来存储需要下载的图片的url链接,需要给一个列表。
  2. 当文件下载完成后,会把文件下载的相关信息存储到itemimages属性中。比如下载路径、下载的url和文件的校验码等。
  3. 在配置文件 settings.py中配置 IMAGES_STORE,这个配置是用来设置文件下载下来的路径。
  4. 启动 pipeline:在 ITEM_PIPELINES中设置 scrapy.pipelines.images.ImagesPipeline:1

map函数

srcs = list(map(lambda x: response.urljoin(x), srcs))
map(function, iterable, ...)
  • function – 函数
  • iterable – 一个或多个序列
map(lambda x: x ** 2, [1, 2, 3, 4, 5])  # 使用 lambda 匿名函数
[1, 4, 9, 16, 25]

User-Agent随机请求头

http://www.useragentstring.com

1、Middleware.py文件如下设置

class UserAgentDownloadMiddleware(object):USER_AGENTS = ['Mozilla/5.0 (compatible; MSIE 9.0; AOL 9.0; Windows NT 6.0; Trident/5.0)','Mozilla/5.0 (compatible; MSIE 9.0; AOL 9.1; AOLBuild 4334.5012; Windows NT 6.0; WOW64; Trident/5.0)','Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:78.0) Gecko/20100101 Firefox/78.0','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36','Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9a3) Gecko/20070409 BonEcho/2.0.0.3','Mozilla/5.0 (Windows NT 10.0; WOW64; rv:77.0) Gecko/20100101 Firefox/77.0']def process_request(self, request, spider):user_agent = random.choice(self.USER_AGENTS)request.headers['User-Agent'] = user_agent

注:USER_AGENTS必须为列表,才能使用random.choice进行选择

2、爬虫文件如下配置

def parse(self, response):user_agent = json.loads(response.text)['user-agent']print(user_agent)yield scrapy.Request(self.start_urls[0], dont_filter=True)

其中yield为一直发送请求

dont_filter=True为设置不删除重复的链接,即可以一直访问相同的链接。

设置代理方法:

request.mate['proxy']=proxy

scrapy通过twisted实现异步存入数据库

代码如下:

from twisted.enterprise import adbapi
from pymysql import cursors
class JianshuTwistedPipeline(object):def __init__(self):dbparms = {'host': '127.0.0.1','user': 'root','password': 'root','database': 'jianshu','port': 3306,'charset': 'utf8',# 此处必须填写cursor类,否则回直接使用默认cursor类'cursorclass': cursors.DictCursor}self.dbpool = adbapi.ConnectionPool('pymysql', **dbparms)self._sql = None@propertydef sql(self):if not self._sql:self._sql = """insert into article(id,title,content,origin_url,article_id) values (null ,%s,%s,%s,%s)"""return self._sqlreturn self._sqldef process_item(self, item, spider):# 此处为添加item,将调价item给self.insert_item函数处理defer = self.dbpool.runInteraction(self.insert_item, item)defer.addErrback(self.handle_error, item, spider)return item# 定义插入数据库代码def insert_item(self, cursor, item):cursor.execute(self.sql, (item['title'], item['content'], item['origin_url'], item['article_id']))# 处理错误代码def handle_error(self, error, item, spider):print('=' * 10 + 'error' + '=' * 10)print(error)print('=' * 10 + 'error' + '=' * 10)
http://www.lryc.cn/news/2414774.html

相关文章:

  • 网络入门基础(基本网络的了解和配置)
  • 快手狂人
  • 虚拟环境安装,ubuntu18和16的一些不同
  • 简报 | 欧洲区块链投资 将达到8.15亿欧元
  • 亚马逊云科技为企业出海提供全方位的安全合规保障
  • EXCEL难题一网打尽 无意间看到的 转过来 自己看看
  • 探索Web前端:新手必看的入门指南
  • js实现数组浅拷贝和深拷贝
  • 秋招Java开发----牛客刷题错题总结
  • Qt 将中文汉字转成拼音与简拼
  • 【QQ技术】群文件报毒怎样下载?~ 变相绕过QQ复杂检验过程
  • Android版xx助手之天天酷跑外挂详细分析
  • 数仓之归因分析
  • 百度你皮 调教百度
  • 150首中国翻唱韩国原歌曲
  • 求水仙花_500万株水仙花争相绽放,这个日本小岛人少冬天还能看花!| 日本淡路岛...
  • python自动化运维平台开发_开发自动化运维管理平台
  • [Python爬虫]煎蛋网OOXX妹子图爬虫(1)——解密图片地址
  • 南大通用GBase 8d产品ldapsearch命令详解
  • 3-8译码器
  • 电子元器件基础6---三极管
  • Java Applet的运行原理和生命周期
  • 运维面板推荐
  • SHELL 基础语法
  • EVN双归组网环路问题解决
  • dbscan算法_聚类算法_层次聚类_密度聚类(dbscan,meanshift)_划分聚类(Kmeans)详解
  • windows命令_在Windows中管理无线网络的8个CMD命令
  • 对达梦数据库CASE_SENSITIVE参数的探讨
  • KVM详解,太详细太深入了,经典
  • Android性能优化第(六)篇---TraceView 分析图怎么看