How can I get text from html fragment in scrapy? - scrapy

all
Here is some html string I got from website by ajax request
{
"data":{
label: 'description',
values: ['<p class="description">'
'someting'
'<br>'
'<br>'
'<b>mytitle_1</b>'
'<br>'
'<br>'
'something_1'
'<br>'
'<br>'
'<b>mytitle_2</b>'
'<br>'
'<br>'
'something_2'
'</p>']}
}
the value of the values key is html fragment, how can I get the all text inside the data["values"].
I'm using scrapy and is there any way to parse it by scrapy response get method?

Yes, you just need to extract the html content, cast it as a scrapy selector and use xpath('//text()').getall() on it.
Example:
from scrapy.selector import Selector
resp_json = {
"data":{
'label': 'description',
'values': ['<p class="description">'
'someting'
'<br>'
'<br>'
'<b>mytitle_1</b>'
'<br>'
'<br>'
'something_1'
'<br>'
'<br>'
'<b>mytitle_2</b>'
'<br>'
'<br>'
'something_2'
'</p>']}
}
a = Selector(text=resp_json['data']['values'][0], type='html')
content = a.xpath('//text()').getall()
print(content)
Output:
['someting', 'mytitle_1', 'something_1', 'mytitle_2', 'something_2']

Related

Barcode CODE_128 using PrintHTML with Qz Tray

Good Day All,
Right now, i'm trying to print using HTML with Qz-Tray. Can i make a barcode on that template HTML. The Problem is, that HTML template is STRING so it can not be change it using Javascript and I'm Trying to use Libre Font 128 Font Family but still not working.
https://www.w3schools.com/howto/tryit.asp?font=Libre%20Barcode%20128 i want to use that library, in this
function printHTML() {
var config = getUpdatedConfig();
var colA = '<h2>* QZ Print Plugin HTML Printing *</h2>' +
'<span style="color: #F00;">Version:</span> ' + qzVersion + '<br/>' +
'<span style="color: #F00;">Visit:</span> https://qz.io/';
var colB = '<img src="' + getPath() + '/assets/img/image_sample.png">';
var printData = [
{
type: 'html',
format: 'plain',
data: '<html>' +
' <table style="font-family: monospace; border: 1px;">' +
' <tr style="height: 6cm;">' +
' <td valign="top">' + colA + '</td>' +
' <td valign="top">' + colB + '</td>' +
' </tr>' +
' </table>' +
'</html>'
}
];
qz.print(config, printData).catch(displayError);
}
or this https://barcode-coder.com/en/barcode-jquery-plugin-201.html

How to validate multiple user inputs within just one popup using Vue-SweetAlert2

As a coding training, right now I'm making a web page where you can click a "Create" button, which triggers a popup, where you are supposed to fill in 6 data inputs, whose input style varies like text, select etc. (See the code and the attached image below)
<template>
<v-btn class="create-button" color="yellow" #click="alertDisplay">Create</v-btn>
<br/>
<p>Test result of createCustomer: {{ createdCustomer }}</p>
</div>
</template>
<script>
export default {
data() {
return {
createdCustomer: null
}
},
methods: {
alertDisplay() {
const {value: formValues} = await this.$swal.fire({
title: 'Create private customer',
html: '<input id="swal-input1" class="swal2-input" placeholder="Customer Number">' +
'<select id="swal-input2" class="swal2-input"> <option value="fi_FI">fi_FI</option> <option value="sv_SE">sv_SE</option> </select>'
+
'<input id="swal-input3" class="swal2-input" placeholder="regNo">' +
'<input id="swal-input4" class="swal2-input" placeholder="Address">' +
'<input id="swal-input5" class="swal2-input" placeholder="First Name">' +
'<input id="swal-input6" class="swal2-input" placeholder="Last Name">'
,
focusConfirm: false,
preConfirm: () => {
return [
document.getElementById('swal-input1').value,
document.getElementById('swal-input2').value,
document.getElementById('swal-input3').value,
document.getElementById('swal-input4').value,
document.getElementById('swal-input5').value,
document.getElementById('swal-input6').value
]
}
})
if (formValues) {
this.createdCustomer = this.$swal.fire(JSON.stringify(formValues));
console.log(this.createdCustomer);
}
}
}
}
</script>
Technically, it's working. The popup shows up when the "create" button is clicked, and you can fill in all the 6 blanks and click the "OK" button as well. But I want to add some functionalities that check if the user inputs are valid, I mean things like
address should be within 50 characters
firstName should be within 20 characters
customerNumber should include both alphabets and numbers
and so on.
If it were C or Java, I could probably do something like
if(length <= 50){
// proceed
} else {
// warn the user that the string is too long
}
, but when it comes to validating multiple inputs within a single popup using Vue-SweetAlert2, I'm not sure how to do it, and I haven't been able to find any page that explains detailed enough.
If it were just a single input, maybe you could use inputValidor like this
const {value: ipAddress} = await Swal.fire({
title: 'Enter an IP address',
input: 'text',
inputValue: inputValue,
showCancelButton: true,
inputValidator: (value) => {
if (!value) {
return 'You need to write something!'
}
}
})
if (ipAddress) {
Swal.fire(`Your IP address is ${ipAddress}`)
}
, but this example only involves "one input". Plus, what this checks is just "whether an IP address has been given or not" (, which means whether there is a value or not, and it doesn't really check if the length of the IP address is correct and / or whether the input string consists of numbers / alphabets).
On the other hand, what I'm trying to do is to "restrict multiple input values (such as the length of the string etc)" "within a single popup". Any idea how I am supposed to do this?
Unfortunately the HTML tags to restrict inputs (e.g. required, pattern, etc.) do not work (see this issues),
so I find two work around.
Using preConfirm as in the linked issues
You could use preConfirm and if/else statement with Regex to check your requirement, if they are not satisfied you could use Swal.showValidationMessage(error).
const{value:formValue} = await Swal.fire({
title: "Some multiple input",
html:
<input id="swal-input1" class="swal-input1" placeholder="name"> +
<input id="swal-input2" class="swal-input2" placeholder="phone">,
preConfirm: () => {
if($("#swal-input1").val() !== "Joe"){
Swal.showValidationMessage("your name must be Joe");
} else if (!('[0-9]+'.test($("#swal-input2").val())){
Swal.showValidationMessage("your phone must contain some numbers");
}
}
});
Using Bootstrap
In this way Bootstrap does the check at the validation, you need to include class="form-control" in your input class and change a little your html code.
If some conditions fails, the browser shows a validation message for each fields, in the order they are in the html code.
const {value: formValue} = await Swal.fire({
title: 'Some multiple inputs',
html:
'<form id="multiple-inputs">' +
'<div class="form-group">' +
'<input type="text" class="form-control swal-input1" id="swal-input1" min=2 max=4 required>' +
'</div>' +
'<div class="form-group">' +
'<input type="text" class="form-control swal-input2" id="swal-input2" placeholder="Name" pattern="[A-Za-z]" required>' +
'</div>' +
'</form>',
});
I have tried both the solution, actually only with Bootstrap3 but it should work also with the latest release.

Vue.js method returning undefined when accessing data

I'm using Vue.js to populate a list of locations, and using a method that should return a formatted map link using the address.
The problem is that in the method, trying to return this.Address ends up in undefined. Here's what I've got:
// the Vue model
pbrplApp = new Vue({
el: '#pbrpl-locations',
data: {
'success' : 0,
'errorResponse' : '',
'wsdlLastResponse' : '',
't' : 0,
'familyId' : 0,
'brandId' : 0,
'srchRadius' : 0,
'lat' : 0,
'lon' : 0,
'response' : []
},
methods: {
getDirections: function(address,city,st,zip){
// THIS Doesn't work:
//var addr = this.Address + ',' + this.City + ',' + this.State + ' ' + this.Zip;
var addr = address + ',' + city + ',' + st + ' ' + zip;
addr = addr.replace(/ /g, '+');
return 'https://maps.google.com/maps?daddr=' + addr;
}
}
});
// the template
<ul class="pbrpl-locations">
<template v-for="(location,idx) in response">
<li class="pbrpl-location" :data-lat="location.Latitude" :data-lon="location.Longitude" :data-premise="location.PremiseType" :data-acct="location.RetailAccountNum">
<div class="pbrpl-loc-idx">{{idx+1}}</div>
<div class="pbrpl-loc-loc">
<div class="pbrpl-loc-name">{{location.Name}}</div>
<div class="pbrpl-loc-address">
<a :href="getDirections(location.Address,location.City,location.State,location.Zip)" target="_blank">
{{location.Address}}<br>
{{location.City}}, {{location.State}} {{location.Zip}}
</a>
</div>
</div>
</li>
</template>
</ul>
Right now, I'm having to pass the address, city, state and zip code back to the model's method, which I know is wrong - but I can't find anything in the vue.js docs on the proper way to get the values.
What's the proper way to get the method to reference "this" properly? Thanks for your help.
this.Address doesn't work because Address is not part of your data. It looks like what you are doing is iterating through response, which somehow gets populated with locations.
You could just pass location to getDirections instead of each of the parameters.
getDirections(location){
let addr = location.Address+ ',' + location.City + ',' + location.State + ' ' + location.Zip
....
}
And change your template to
<a :href="getDirections(location)" target="_blank">
In general, in Vue methods, this will refer to the Vue itself, which means that any property that is defined on the Vue (of which properties defined in data are included) will be accessible through this (barring there being a callback inside the method that incorrectly captures this). In your case, you could refer to any of success, errorResponse, wsdlLastResponse, t, familyId, brandId, srchRadius, lat, lon, or response through this in getDirections.

Extjs 4.1.1 How to debug Xtemplete

I am using Ext 4.1.1 version.
I want to know How to debug the Xtemplate. i.e.
e.g.
'<tpl for="outerObject">',
'<tpl for="innerObject">',
'<span class="abc">{myValue}</span>',
'</tpl>',
'</tpl>',
Now I want to know what Value outerObject has, depending upon that want to loop into innerObject, and so on.
Please tell me any way to degug Xtemplate.
The easiest way is to get into the browser's debugger:
tpl: [
'<tpl for="outerObject">',
'{% debugger; %}'
'<tpl for="innerObject">',
'<span class="abc">{myValue}</span>',
'</tpl>',
'</tpl>'
]
You can execute arbitrary inline code in XTemplate. Hence, you can call console.log in order to print some object variable:
'{[console.log(values.outerObject)]}',
I know this is "old" but, if you have your own template or have anyway to come to the template, you can actually add the debugger; command and chrome will jump into the debugger.
extraRowTpl: [
'{%',
'values.view.rowBodyFeature.setupRowData(values.record, values.recordIndex, values);',
'debugger;', **<!-- WILL STOP HERE**
'this.nextTpl.applyOut(values, out, parent);',
'%}',
'<tr class="' + Ext.baseCSSPrefix + 'grid-rowbody-tr {rowBodyCls}">',
'<td class="' + Ext.baseCSSPrefix + 'grid-cell-rowbody' + ' ' + Ext.baseCSSPrefix + 'grid-cell ' + Ext.baseCSSPrefix + 'grid-td" colspan="{rowBodyColspan}">',
'<div class="' + Ext.baseCSSPrefix + 'grid-rowbody' + ' {rowBodyDivCls}">{rowBody}</div>',
'</td>',
'</tr>']
Hope I could help!
Greetz

How to dynamically set itemTpl based on the items in some other store in sencha touch?

I have 2 stores. SortStore and WorkStore.
This is my WorkStore fields in the model:
{name: 'domainName',type:'string',mapping:'DomainName'},
{name: 'objectId',type:'string',mapping:'ObjectID'},
{name: 'serverName',type:'string',mapping:'ServerName'},
{name: 'sourceWorkset',type:'string',mapping:'SourceWorkset'},
{name: 'sourceWorkstep',type:'string',mapping:'SourceWorkstep'},
This is my SortStore fields in the model:
['name', 'value']
I want to display data from workstore in a list based on the items in the sortstore. if sort store has domain name and object id. The list should populate only those values from the workstore. Stores are getting dynamically loaded by webservice call.
{
xtype:'list',
id:'workitemlist',
// store:'WorkitemStore',
itemTpl:'<table><tr><td valign="top"><img src="{workitemImage}" width=20px height=22px />' +
' </td><td><span><b>{workitemName}</b></span> <br/>' +
'<span class="label">Object Id:</span> {objectId} <br /><span class="label">' +
'Source Workstep: </span>{sourceWorkstep}</td> </tr></table>'
}
Instead of printing all these in itemTpl I need only those present in sortstore to get populated. How to dynamically set this itemTpl based on the items in some other store. Any help is appreciated.
We can dynamically set itemTpl this way:
var template = '<table><tr><td valign="top"><img src="{Image}"' +
' width=20px height=22px />' +
' </td><td><span><b>{Name}</b></span> <br/>';
var myStore = Ext.getStore('RealStore');
if (myStore != null) {
myStore.each(function (record) {
if (record.get('field')) {
template += '<span class="label">Domain Name:</span>' +
' {field} <br/>';
}
}
Not sure if that's the best way but the way I have implemented it in past was to keep JSON of templateId(using differentiating field e.g. "tpl_"+field) & templateContent for my app and load it on startup in a variable(tpls). Once it is loaded I can refer it from anywhere like this:
var styleTemplate = eval('tpls.tpl_' + rec.field);
and then pass it to list like this:
{
xtype: 'list',
itemTpl : styleTemplate,
store : listStore,
id : 'ilid',
layout : 'fit'
}