Nokogiri doesn't work using css selector - css

My code:
require 'rubygems'
require 'nokogiri'
require 'open-uri'
PAGE_URL = "http://www.whoscored.com/Teams/1799/Fixtures/Spain-Almeria"
page = Nokogiri::HTML(open(PAGE_URL))
CSS_SELECTOR = "a.match-link.match-report.rc"
links = page.css(CSS_SELECTOR)
puts links.length # => RESULT = 0
puts links[0].text # => RESULT = none
puts links[0]["href"] # => RESULT = ./read_stats.rb:15:in `<main>': undefined method `text' for nil:NilClass (NoMethodError)
The results should be:
1
Match Report
/Matches/738463/MatchReport
But my results are:
0
./read_stats.rb:15:in `<main>': undefined method `text' for nil:NilClass (NoMethodError)
It doesn't work, and I dont see the problem...
Thanks.

You need to render the page before you can scrape it.
require 'watir-webdriver'
require 'nokogiri'
$browser = Watir::Browser.start "http://www.whoscored.com/Teams/1799/Fixtures/Spain-Almeria"
$page_html = Nokogiri::HTML.parse($browser.html)
$page_html.css("td[#class='toolbar right']").each do |me|
print "#{me.count}\n#{me.text}\n#{me.css("a").map{|link| link['href']}[0]}\n\n"
end
Try out watir.com

Related

Wordpress/Woocommerce - blank 'new post' admin page, can't create posts

I have had the store for years, but never added blog posts, so I am not sure how long this has been broken - it may have been from the very first version.
I am now looking at adding a blog to the store but selected 'new post' just gives a blank screen - the console in chrome shows the following errors.
> JQMIGRATE: Migrate is installed, version 1.4.1
data.min.js?ver=4.2.0:1 Uncaught TypeError: Object(...) is not a function
at Module.308 (data.min.js?ver=4.2.0:1)
at r (data.min.js?ver=4.2.0:1)
at wp.data.0 (data.min.js?ver=4.2.0:1)
at data.min.js?ver=4.2.0:1
post-new.php:2018 Uncaught TypeError: Cannot read property 'use' of undefined
at post-new.php:2018
at post-new.php:2020
The code is so abstracted that I am not sure what it is actually doing - but all the code is in wp-includes/js/dist/
And the bit of code throwing the error looks like this (the second line is highlighted as failing).
var A = {
reducer: Object(f.flowRight)([S("reducerKey"), S("selectorName")])(function() {
var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : new m.a
, e = arguments.length > 1 ? arguments[1] : void 0;
switch (e.type) {
case "START_RESOLUTION":
case "FINISH_RESOLUTION":
var r = "START_RESOLUTION" === e.type
, n = new m.a(t);
return n.set(e.args, r),
n;
case "INVALIDATE_RESOLUTION":
var o = new m.a(t);
return o.delete(e.args),
o
}
return t
}),
I have tried this in chrome and edge, both get exactly the same result - same error, but a bit less informative in the edge console.
It seems to be a guttenburg/block editor issue, the old classic editor, can be enabled using this plug in
https://wordpress.org/plugins/classic-editor/

Mongoengine serialize dictionary (with nested dicts)?

I've created a dictionary from an Uploaded file in Django.
This dictionary has a nested list of dictionaries:
file = {"name": "filename", "sections": [{"section_name": "string", "lines": [{line_number: 0, "line"; "data"}]}], "etc": "etc"}
The model represents the dictionaries depth too.
class Line(EmbeddedDocument):
line_number = IntField()
line = StringField()
definition = ReferenceField(Definition)
class Section(EmbeddedDocument):
section_name = StringField()
lines = EmbeddedDocumentListField(Line))
class File(Document):
name = StringField()
sections = EmbeddedDocumentListField(Section))
created_on = DateTimeField()
created_by = StringField()
modified_on = DateTimeField()
modified_by = StringField()
In the POST I have the following to chop the file up into the above Dict (the file is a simple text file):
file= {}
with open(os.path.join(path, filename + ".txt"), 'r') as temp_file:
filelines = temp_file.readlines()
sections = []
section = {}
lines = []
for i, l in enumerate(filelines):
if i == 0:
section["section_name"] = "Top"
elif '*' in l:
if l.index('*') == 0 and '*' not in lines[len(lines) - 2"line"]:
section["lines"] = lines
lines = []
sections.append(section)
section = dict()
section["section_name"] = filelines[i + 1][1:-2]
line = {"line_number": i + 1, "line": l}
lines.append(line)
section['lines'] = lines
sections.append(section)
file["name"] = filename
file["sections"] = sections
I will tidy this up eventually.
Once the dict has been made how do I serialise it using the serializer?
Is it possible to insert this into a serializer?
If not how can I get it all into the database with validation?
I've tried json.dumps() and JsonRequst() then putting them in data= for the serializer but get Unable to get repr for <class '....'>
I'm pretty new to Django and MongoDB so if you need more info I can provide :)
Thanks!
Update
Change the model's List Fields to EmbeddedDocumentListField as suggest in the answer.
Answered
Thanks to Boris' suggestion below it pointed me to an error I wasn't getting initially. I had a typo and passing the dict directly into FileSerializer(data=file) works like a charm! :)
James!
The easiest way to validate that your incoming JSONs adhere to the Mongoengine Documents schema that you've specified is to use DRF-Mongoengine's DocumentSerializer.
Basically, what you need to do is create a serializer
serializers.py
import rest_framework_mongoengine
class FileSerializer(rest_framework_mongoengine.DocumentSerializer):
class Meta:
fields = '__all__'
model = File
Then you need a view or viewset that makes use of this Serializer to respond to GET/POST/PUT/DELETE requests.
views.py
from rest_framework_mongoengine import viewsets
class FileViewSet(viewsets.ModelViewSet):
lookup_field = 'id'
serializer_class = FileSerializer
def get_queryset(self):
return File.objects.all()
and register this viewset with a router
urls.py
from rest_framework import routers
# this is DRF router for REST API viewsets
router = routers.DefaultRouter()
# register REST API endpoints with DRF router
router.register(r'file', FileViewSet, r"file")
I'd also recommend using EmbeddedDocumentListField instead of ListField(EmbeddedDocumentField(Section)) - it has additional methods.

How to wire up virtual-hyperscript, hyperscript-helpers, and main-loop

I'm looking at an example by substack of using hyperscript, main-loop, and hyperx.
I'd like to recreate this example using hyperscript-helpers to get code similar to Elm. That module says it supports both hyperscript and virtual-hyperscript, so I'm trying virtual-hyperscript.
My code looks like this:
var vdom = require('virtual-dom')
var vh = require('virtual-hyperscript');
var hh = require('hyperscript-helpers')(vh);
var main = require('main-loop')
var div = hh.div;
var span = hh.span;
var h1 = hh.h1;
var loop = main({ times: 0 }, render, vdom)
document.querySelector('#content').appendChild(loop.target)
function render(state) {
return h1('title');
}
And it gives me an error:
Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
What's going wrong? I assume something's not wired up correctly because
console.log(loop.target) //null
If it helps, I can post my html and the browserify build command I'm using
virtual-hyperscript is moved to https://github.com/Matt-Esch/virtual-dom/tree/master/virtual-hyperscript
See README at https://github.com/Raynos/virtual-hyperscript
The virtual-dom/h is just a new version of virtual-hyperscript.

Conditional classname and text (Rails)

I'm pretty new to Rails and trying some basic stuff like conditional classes.
On the 'show' view I have an element that changes styling depending on the stock availability, but also the text changes accordingly.
People keep saying the controller should be as small as possible, but placing this conditional in the view also feels dirty. Is this really the best way?
Current controller:
def show
#tyre = Tyres::Tyre.find_by_id(params[:id])
if #tyre.in_stock
#availability = I18n.t("products.filter.other.in_stock")
#availability_class = 'i-check-circle color--success'
else
#availability = I18n.t("products.filter.other.not_in_stock")
#availability_class = 'i-cross-circle color--important'
end
end
Edit:
Controller:
def show
#tyre = Tyres::Tyre.find_by_id(params[:id])
if #tyre.in_stock
#availability_append = ".in_stock"
else
#availability_append = ".not_in_stock"
end
#availability = I18n.t("products.filter.other#{#availability_append}")
end
View:
.xs-12.description__status
%i{class: (#tyre.in_stock? ? 'i-check-circle color--success' : 'i-cross-circle color--important')}
= #availability
You can clean your controller tyres_controller.rb (i suppose) method,
def show
#tyre = Tyre.find(params[:id]) # I believe you have a model named 'tyre'
end
Then, there will be a file named tyres_helper.rb in your myproject/app/helpers/. Put the following code there,
def tyre_availability(tyre) # it'll return an array with two values, first one is class name, second one is localized value
if tyre.in_stock
return 'i-check-circle color--success', I18n.t("products.filter.other.in_stock")
else
return 'i-cross-circle color--important', I18n.t("products.filter.other.not_in_stock")
end
end
and, in the view you can use,
.xs-12.description__status
%i{:class => tyre_availability(#tyre)[0]}
= tyre_availability(#tyre)[1]

Watir Webdriver <script> Element exists?

I'm attempting to determine after a page loads whether text within a script may be located using Watir WebDriver. I am using Watir-WebDriver to automate our test effort. I cannot figure out how to locate the element and verify the value. Any help?
<script><!--
...
s.events="event9"
...
//--></script>
So, I guess I'm wondering is it possible to search for text within a HTML script using watir webdriver?
Thank you in advance.
UPDATE: Below is the script.
require "rubygems"
require "watir-webdriver"
require "watir-webdriver-performance"
require "rspec"
require "headless"
include Watir
require 'logger'
#path store file: script, data file, logs
path = File.dirname(__FILE__)
#create log file
name_log = 'TEST_0001_bsro_validation_suite'
file = File.open(path + '/logs/' + name_log + '_logFile.log', File::WRONLY | File::APPEND | File::CREAT)
logger = Logger.new(file)
logger.info("=> TEST: 0004_bsro_validation")
#open internet browser
browser = Watir::Browser.new :ff
#go to rebrand website with login info. this may need to be removed.
test_site = 'http://*****:*****#fcac-rebrand.laughlin.com/'
browser.goto(test_site)
load_secs = browser.performance.summary[:response_time]
logger.info("=> Page Load Time: #{load_secs}")
zipcode_input = browser.text_field(:id => 'universal-selectorZip')
# select year; progressive selection
year_select = browser.select_list(:id => 'universal-year')
browser.select_list(:id => 'universal-year', :disabled => 'disabled').wait_while_present
if year_select.exists?
year_select.select '2010'
else
logger.info("=> ERROR: Year Select Not Available")
end
# select make; progressive selection
make_select = browser.select_list(:id => 'universal-make')
browser.select_list(:id => 'universal-make', :disabled => 'disabled').wait_while_present
if make_select.exists?
make_select.select 'Volkswagen'
else
logger.info("=> ERROR: Make Select Not Available")
end
# select model; progressive selection
model_select = browser.select_list(:id => 'universal-model')
browser.select_list(:id => 'universal-model', :disabled => 'disabled').wait_while_present
if model_select.exists?
model_select.select 'Jetta'
else
logger.info("=> ERROR: Model Select Not Available")
end
# select submodel; progressive selection
submodel_select = browser.select_list(:id => 'universal-submodel')
browser.select_list(:id => 'universal-submodel', :disabled => 'disabled').wait_while_present
if submodel_select.exists?
submodel_select.select '2.0T TDI Sedan'
else
logger.info("=> ERROR: Submodel Select Not Available")
end
# input zip code; progressive selection
if zipcode_input.exists?
zipcode_input.set '53202'
else
logger.info("=> ERROR: ZIP Code Select Not Available")
end
browser.button(:id => 'universal-submit-tires-quote').click
browser.script.html.include? "event49"
browser.close
I should add that the event is event49 not 9 in this case. Thanks!
Zeljko has the right approach. However, it would fail if/when there are multiple scripts on the page and the one you want is not first.
If there are multiple script elements, you will have to iterate over them to see if one of the scripts has the value.
browser.scripts.any?{ |s| s.html.include? "event9" }
#=> true
This should do it:
browser.script.html.include? "event9"
#=> true

Resources